1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 08:42:41 +01:00

Project list and profile view modifications

Summary: Added some change on the project's list view, to show information about
active tasks, population, etc. Also modified the "profile view", and added a class "PhabricatorProfileView" to render the profile, both on projects and users.

Test Plan: play around the project directory :)

Reviewers: epriestley ericfrenkiel

CC:

Differential Revision: 477
This commit is contained in:
Cristian Adamo 2011-06-18 05:13:56 -03:00
parent 565cc43f27
commit 7851b6573f
27 changed files with 664 additions and 263 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE phabricator_project.project
ADD status varchar(32) not null;

View file

@ -63,7 +63,7 @@ celerity_register_resource_map(array(
),
'aphront-headsup-action-list-view-css' =>
array(
'uri' => '/res/c0ef93b6/rsrc/css/aphront/headsup-action-list-view.css',
'uri' => '/res/af3dff49/rsrc/css/aphront/headsup-action-list-view.css',
'type' => 'css',
'requires' =>
array(
@ -154,7 +154,7 @@ celerity_register_resource_map(array(
),
'differential-core-view-css' =>
array(
'uri' => '/res/dd6b4ca9/rsrc/css/application/differential/core.css',
'uri' => '/res/438fe316/rsrc/css/application/differential/core.css',
'type' => 'css',
'requires' =>
array(
@ -1048,12 +1048,12 @@ celerity_register_resource_map(array(
),
'phabricator-profile-css' =>
array(
'uri' => '/res/adcdb5f3/rsrc/css/application/people/profile.css',
'uri' => '/res/4cb0251e/rsrc/css/application/profile/profile-view.css',
'type' => 'css',
'requires' =>
array(
),
'disk' => '/rsrc/css/application/people/profile.css',
'disk' => '/rsrc/css/application/profile/profile-view.css',
),
'phabricator-remarkup-css' =>
array(
@ -1156,23 +1156,6 @@ celerity_register_resource_map(array(
'uri' => '/res/pkg/a452c449/core.pkg.css',
'type' => 'css',
),
'c9226a80' =>
array (
'name' => 'differential.pkg.css',
'symbols' =>
array (
0 => 'differential-core-view-css',
1 => 'differential-changeset-view-css',
2 => 'differential-revision-detail-css',
3 => 'differential-revision-history-css',
4 => 'differential-table-of-contents-css',
5 => 'differential-revision-comment-css',
6 => 'differential-revision-add-comment-css',
7 => 'differential-revision-comment-list-css',
),
'uri' => '/res/pkg/c9226a80/differential.pkg.css',
'type' => 'css',
),
'da416e1c' =>
array (
'name' => 'differential.pkg.js',
@ -1222,6 +1205,23 @@ celerity_register_resource_map(array(
'uri' => '/res/pkg/df91920b/workflow.pkg.js',
'type' => 'js',
),
55967526 =>
array (
'name' => 'differential.pkg.css',
'symbols' =>
array (
0 => 'differential-core-view-css',
1 => 'differential-changeset-view-css',
2 => 'differential-revision-detail-css',
3 => 'differential-revision-history-css',
4 => 'differential-table-of-contents-css',
5 => 'differential-revision-comment-css',
6 => 'differential-revision-add-comment-css',
7 => 'differential-revision-comment-list-css',
),
'uri' => '/res/pkg/55967526/differential.pkg.css',
'type' => 'css',
),
),
'reverse' =>
array (
@ -1234,14 +1234,14 @@ celerity_register_resource_map(array(
'aphront-table-view-css' => 'a452c449',
'aphront-tokenizer-control-css' => 'a452c449',
'aphront-typeahead-control-css' => 'a452c449',
'differential-changeset-view-css' => 'c9226a80',
'differential-core-view-css' => 'c9226a80',
'differential-revision-add-comment-css' => 'c9226a80',
'differential-revision-comment-css' => 'c9226a80',
'differential-revision-comment-list-css' => 'c9226a80',
'differential-revision-detail-css' => 'c9226a80',
'differential-revision-history-css' => 'c9226a80',
'differential-table-of-contents-css' => 'c9226a80',
'differential-changeset-view-css' => '55967526',
'differential-core-view-css' => '55967526',
'differential-revision-add-comment-css' => '55967526',
'differential-revision-comment-css' => '55967526',
'differential-revision-comment-list-css' => '55967526',
'differential-revision-detail-css' => '55967526',
'differential-revision-history-css' => '55967526',
'differential-table-of-contents-css' => '55967526',
'diffusion-commit-view-css' => '03ef179e',
'javelin-behavior' => 'db95a6d0',
'javelin-behavior-aphront-basic-tokenizer' => '2892314d',

View file

@ -419,16 +419,19 @@ phutil_register_library_map(array(
'PhabricatorPeopleProfileController' => 'applications/people/controller/profile',
'PhabricatorPeopleProfileEditController' => 'applications/people/controller/profileedit',
'PhabricatorPreferencesController' => 'applications/preferences/controller/base',
'PhabricatorProfileView' => 'view/layout/profile',
'PhabricatorProject' => 'applications/project/storage/project',
'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
'PhabricatorProjectController' => 'applications/project/controller/base',
'PhabricatorProjectDAO' => 'applications/project/storage/base',
'PhabricatorProjectEditController' => 'applications/project/controller/edit',
'PhabricatorProjectListController' => 'applications/project/controller/list',
'PhabricatorProjectProfile' => 'applications/project/storage/profile',
'PhabricatorProjectProfileController' => 'applications/project/controller/profile',
'PhabricatorProjectProfileEditController' => 'applications/project/controller/profileedit',
'PhabricatorProjectQuickCreateController' => 'applications/project/controller/quickcreate',
'PhabricatorProjectStatus' => 'applications/project/constants/status',
'PhabricatorProjectTransactionSearch' => 'applications/project/transactions/search',
'PhabricatorRedirectController' => 'applications/base/controller/redirect',
'PhabricatorRemarkupRuleDifferential' => 'infrastructure/markup/remarkup/markuprule/differential',
'PhabricatorRemarkupRuleDiffusion' => 'infrastructure/markup/remarkup/markuprule/diffusion',
@ -877,15 +880,16 @@ phutil_register_library_map(array(
'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController',
'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController',
'PhabricatorPreferencesController' => 'PhabricatorController',
'PhabricatorProfileView' => 'AphrontView',
'PhabricatorProject' => 'PhabricatorProjectDAO',
'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO',
'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController',
'PhabricatorProjectController' => 'PhabricatorController',
'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
'PhabricatorProjectEditController' => 'PhabricatorProjectController',
'PhabricatorProjectListController' => 'PhabricatorProjectController',
'PhabricatorProjectProfile' => 'PhabricatorProjectDAO',
'PhabricatorProjectProfileController' => 'PhabricatorProjectController',
'PhabricatorProjectProfileEditController' => 'PhabricatorProjectController',
'PhabricatorProjectQuickCreateController' => 'PhabricatorProjectController',
'PhabricatorRedirectController' => 'PhabricatorController',
'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName',

View file

@ -76,7 +76,8 @@ class AphrontDefaultApplicationConfiguration
'edit/(?:(?P<id>\d+)/(?:(?P<view>\w+)/)?)?$'
=> 'PhabricatorPeopleEditController',
),
'/p/(?P<username>\w+)/$' => 'PhabricatorPeopleProfileController',
'/p/(?P<username>\w+)/(?:(?P<page>\w+)/)?$'
=> 'PhabricatorPeopleProfileController',
'/profile/' => array(
'edit/$' => 'PhabricatorPeopleProfileEditController',
),
@ -196,8 +197,9 @@ class AphrontDefaultApplicationConfiguration
'/project/' => array(
'$' => 'PhabricatorProjectListController',
'edit/(?:(?P<id>\d+)/)?$' => 'PhabricatorProjectEditController',
'view/(?P<id>\d+)/$' => 'PhabricatorProjectProfileController',
'edit/(?:(?P<id>\d+)/)?$' => 'PhabricatorProjectProfileEditController',
'view/(?P<id>\d+)/(?:(?P<page>\w+)/)?$'
=> 'PhabricatorProjectProfileController',
'affiliation/(?P<id>\d+)/$'
=> 'PhabricatorProjectAffiliationEditController',
'quickcreate/$' => 'PhabricatorProjectQuickCreateController',

View file

@ -8,6 +8,7 @@
phutil_require_module('phabricator', 'aphront/response/webpage');
phutil_require_module('phabricator', 'applications/base/controller/base');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phutil', 'utils');

View file

@ -19,9 +19,11 @@
class PhabricatorPeopleProfileController extends PhabricatorPeopleController {
private $username;
private $page;
public function willProcessRequest(array $data) {
$this->username = $data['username'];
$this->username = idx($data, 'username');
$this->page = idx($data, 'page');
}
public function processRequest() {
@ -83,44 +85,56 @@ class PhabricatorPeopleProfileController extends PhabricatorPeopleController {
}
}
foreach ($links as $k => $link) {
$links[$k] = '<li>'.$link.'</li>';
// TODO: perhaps, if someone wants to add to the profile of the user the
// ability to show the task/revisions where he is working/commenting
// on, this has to be changed to something like
// |$this->page = key($pages)|, since the "page" regexp was added to
// the aphrontconfiguration.
if (empty($links[$this->page])) {
$this->page = 'action';
}
$links =
'<ul class="profile-nav-links">'.
implode("\n", $links).
'</ul>';
$title = nonempty($profile->getTitle(), 'Untitled Document');
$username_tag =
'<h1 class="profile-username">'.
phutil_escape_html($user->getUserName()).
'</h1>';
$realname_tag =
'<h2 class="profile-realname">'.
'('.phutil_escape_html($user->getRealName()).')'.
'</h2>';
$title_tag =
'<h2 class="profile-usertitle">'.
phutil_escape_html($title).
'</h2>';
switch ($this->page) {
default:
$content = $this->renderBasicInformation($user, $profile);
break;
}
$src_phid = $profile->getProfileImagePHID();
if (!$src_phid) {
$src_phid = $user->getProfileImagePHID();
}
$src = PhabricatorFileURI::getViewURIForPHID($src_phid);
$picture = PhabricatorFileURI::getViewURIForPHID($src_phid);
$title = nonempty($profile->getTitle(), 'Untitled Document');
$realname = '('.$user->getRealName().')';
$picture = phutil_render_tag(
'img',
$profile = new PhabricatorProfileView();
$profile->setProfilePicture($picture);
$profile->setProfileNames(
$user->getUserName(),
$realname,
$title);
foreach ($links as $page => $name) {
if (is_integer($page)) {
$profile->addProfileItem(
phutil_render_tag(
'span',
array(),
$name));
} else {
$profile->addProfileItem($page);
}
}
$profile->appendChild($content);
return $this->buildStandardPageResponse(
$profile,
array(
'class' => 'profile-image',
'src' => $src,
'title' => $user->getUsername(),
));
}
require_celerity_resource('phabricator-profile-css');
private function renderBasicInformation($user, $profile) {
$blurb = nonempty(
$profile->getBlurb(),
'//Nothing is known about this rare specimen.//');
@ -158,30 +172,6 @@ class PhabricatorPeopleProfileController extends PhabricatorPeopleController {
</div>
</div>';
$profile =
'<table class="phabricator-profile-master-layout">
<tr>
<td class="phabricator-profile-navigation">'.
$username_tag.
$realname_tag.
$title_tag.
'<hr />'.
$picture.
'<hr />'.
$links.
'<hr />'.
'</td>
<td class="phabricator-profile-content">'.
$content.
'</td>
</tr>
</table>';
return $this->buildStandardPageResponse(
$profile,
array(
'title' => $user->getUsername(),
));
return $content;
}
}

View file

@ -14,7 +14,7 @@ phutil_require_module('phabricator', 'applications/people/controller/base');
phutil_require_module('phabricator', 'applications/people/storage/profile');
phutil_require_module('phabricator', 'applications/people/storage/user');
phutil_require_module('phabricator', 'applications/people/storage/useroauthinfo');
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/layout/profile');
phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');

View file

@ -60,6 +60,7 @@ class PhabricatorPeopleProfileEditController
}
}
$error_view = null;
if ($errors) {
$error_view = new AphrontErrorView();
$error_view->setTitle('Form Errors');
@ -112,4 +113,4 @@ class PhabricatorPeopleProfileEditController
));
}
}
}

View file

@ -0,0 +1,58 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorProjectStatus {
const UNKNOWN = 0;
const NOT_STARTED = 1;
const IN_PROGRESS = 2;
const REVIEW_PROCESS = 3;
const RELEASED = 4;
const COMPLETED = 5;
const DEFERRED = 6;
const ONGOING = 7;
public static function getNameForStatus($status) {
static $map = array(
self::UNKNOWN => 'Who knows?',
self::NOT_STARTED => 'Not started',
self::IN_PROGRESS => 'In progress',
self::ONGOING => 'Ongoing',
self::REVIEW_PROCESS => 'Review process',
self::RELEASED => 'Released',
self::COMPLETED => 'Completed',
self::DEFERRED => 'Deferred',
);
return idx($map, coalesce($status, '?'), $map[self::UNKNOWN]);
}
public static function getStatusMap() {
return array(
self::UNKNOWN => 'Who knows?',
self::NOT_STARTED => 'Not started',
self::IN_PROGRESS => 'In progress',
self::ONGOING => 'Ongoing',
self::REVIEW_PROCESS => 'Review process',
self::RELEASED => 'Released',
self::COMPLETED => 'Completed',
self::DEFERRED => 'Deferred',
);
}
}

View file

@ -0,0 +1,12 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorProjectStatus.php');

View file

@ -24,10 +24,50 @@ class PhabricatorProjectListController
$projects = id(new PhabricatorProject())->loadAllWhere(
'1 = 1 ORDER BY id DESC limit 100');
$author_phids = mpull($projects, 'getAuthorPHID');
$handles = id(new PhabricatorObjectHandleData($author_phids))
->loadHandles();
$rows = array();
foreach ($projects as $project) {
$documents = new PhabricatorProjectTransactionSearch($project->getPHID());
// search all open documents by default
$documents->setSearchOptions();
$documents = $documents->executeSearch();
$documents_types = igroup($documents,'documentType');
$tasks = idx(
$documents_types,
PhabricatorPHIDConstants::PHID_TYPE_TASK);
$tasks_amount = count($tasks);
// TODO: set up a relationship between the project and the arcanist's
// project, to be able get the revisions.
$revisions = idx(
$documents_types,
PhabricatorPHIDConstants::PHID_TYPE_DREV);
$revisions_amount = count($revisions);
$profile = $project->getProfile();
$affiliations = $project->loadAffiliations();
$population = count($affiliations);
$status = PhabricatorProjectStatus::getNameForStatus(
$project->getStatus());
$blurb = nonempty(
$profile->getBlurb(),
'Oops!, nothing is known about this elusive project.');
$blurb = $this->textWrap($blurb, $columns = 100);
$rows[] = array(
phutil_escape_html($project->getName()),
phutil_escape_html($blurb),
$handles[$project->getAuthorPHID()]->renderLink(),
phutil_escape_html($population),
phutil_escape_html($status),
phutil_escape_html($tasks_amount),
// phutil_escape_html($revisions_amount),
phutil_render_tag(
'a',
array(
@ -42,11 +82,23 @@ class PhabricatorProjectListController
$table->setHeaders(
array(
'Project',
'Blurb',
'Mastermind',
'Population',
'Status',
'Open Tasks',
// 'Open Revisions',
'',
));
$table->setColumnClasses(
array(
'pri',
'wide',
'',
'right',
'pri',
'right',
// 'right',
'action',
));
@ -62,4 +114,17 @@ class PhabricatorProjectListController
));
}
private function textWrap($text, $length) {
if (strlen($text) <= $length) {
return $text;
} else {
// TODO: perhaps this could be improved, adding the ability to get the
// last letter and suppress it, if it is one of [(,:; ,etc.
// making "blurb" looks a little bit better. :)
$wrapped = wordwrap($text, $length, '__#END#__');
$end_position = strpos($wrapped, '__#END#__');
$wrapped = substr($text, 0, $end_position).'...';
return $wrapped;
}
}
}

View file

@ -6,8 +6,12 @@
phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/controller/base');
phutil_require_module('phabricator', 'applications/project/storage/project');
phutil_require_module('phabricator', 'applications/project/transactions/search');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/layout/panel');

View file

@ -20,139 +20,168 @@ class PhabricatorProjectProfileController
extends PhabricatorProjectController {
private $id;
private $page;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
$this->id = idx($data, 'id');
$this->page = idx($data, 'page');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$uri = $request->getRequestURI();
$project = id(new PhabricatorProject())->load($this->id);
if (!$project) {
return new Aphront404Response();
}
$profile = id(new PhabricatorProjectProfile())->loadOneWhere(
'projectPHID = %s',
$project->getPHID());
$profile = $project->getProfile();
if (!$profile) {
$profile = new PhabricatorProjectProfile();
}
require_celerity_resource('phabricator-profile-css');
$src_phid = $profile->getProfileImagePHID();
$src = PhabricatorFileURI::getViewURIForPHID($src_phid);
if (!$src_phid) {
$src_phid = $user->getProfileImagePHID();
}
$picture = PhabricatorFileURI::getViewURIForPHID($src_phid);
$picture = phutil_render_tag(
'img',
array(
'class' => 'profile-image',
'src' => $src,
));
$pages = array(
/*
'<h2>Active Documents</h2>',
'tasks' => 'Maniphest Tasks',
'revisions' => 'Differential Revisions',
'<hr />',
'<h2>Workflow</h2>',
'goals' => 'Goals',
'statistics' => 'Statistics',
'<hr />', */
'<h2>Information</h2>',
'edit' => 'Edit Profile',
'affiliation' => 'Edit Affiliation',
);
$links =
'<ul class="profile-nav-links">'.
'<li><a href="/project/edit/'.$project->getID().'/">'.
'Edit Project</a></li>'.
'<li><a href="/project/affiliation/'.$project->getID().'/">'.
'Edit Affiliation</a></li>'.
'</ul>';
if (empty($pages[$this->page])) {
$this->page = 'action'; // key($pages);
}
$blurb = nonempty(
$profile->getBlurb(),
'//Nothing is known about this elusive project.//');
switch ($this->page) {
default:
$content = $this->renderBasicInformation($project, $profile);
break;
}
$factory = new DifferentialMarkupEngineFactory();
$engine = $factory->newDifferentialCommentMarkupEngine();
$blurb = $engine->markupText($blurb);
$affiliations = id(new PhabricatorProjectAffiliation())->loadAllWhere(
'projectPHID = %s ORDER BY IF(status = "former", 1, 0), dateCreated',
$project->getPHID());
$phids = array_merge(
array($project->getAuthorPHID()),
mpull($affiliations, 'getUserPHID'));
$handles = id(new PhabricatorObjectHandleData($phids))
->loadHandles();
$affiliated = array();
foreach ($affiliations as $affiliation) {
$user = $handles[$affiliation->getUserPHID()]->renderLink();
$role = phutil_escape_html($affiliation->getRole());
$status = null;
if ($affiliation->getStatus() == 'former') {
$role = '<em>Former '.$role.'</em>';
$profile = new PhabricatorProfileView();
$profile->setProfilePicture($picture);
$profile->setProfileNames($project->getName());
foreach ($pages as $page => $name) {
if (is_integer($page)) {
$profile->addProfileItem(
phutil_render_tag(
'span',
array(),
$name));
} else {
$uri->setPath('/project/'.$page.'/'.$project->getID().'/');
$profile->addProfileItem(
phutil_render_tag(
'a',
array(
'href' => $uri,
'class' => ($this->page == $page)
? 'phabricator-profile-item-selected'
: null,
),
phutil_escape_html($name)));
}
$affiliated[] = '<li>'.$user.' &mdash; '.$role.$status.'</li>';
}
if ($affiliated) {
$affiliated = '<ul>'.implode("\n", $affiliated).'</ul>';
} else {
$affiliated = '<p><em>No one is affiliated with this project.</em></p>';
}
$timestamp = phabricator_format_timestamp($project->getDateCreated());
$content =
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Basic Information</h1>
<div class="phabricator-profile-info-pane">
<table class="phabricator-profile-info-table">
<tr>
<th>Creator</th>
<td>'.$handles[$project->getAuthorPHID()]->renderLink().'</td>
</tr>
<tr>
<th>Created</th>
<td>'.$timestamp.'</td>
</tr>
<tr>
<th>PHID</th>
<td>'.phutil_escape_html($project->getPHID()).'</td>
</tr>
<tr>
<th>Blurb</th>
<td>'.$blurb.'</td>
</tr>
</table>
</div>
</div>';
$content .=
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Resources</h1>
<div class="phabricator-profile-info-pane">'.
$affiliated.
'</div>
</div>';
$profile_markup =
'<table class="phabricator-profile-master-layout">
<tr>
<td class="phabricator-profile-navigation">'.
'<h1>'.phutil_escape_html($project->getName()).'</h1>'.
'<hr />'.
$picture.
'<hr />'.
$links.
'<hr />'.
'</td>
<td class="phabricator-profile-content">'.
$content.
'</td>
</tr>
</table>';
$profile->appendChild($content);
return $this->buildStandardPageResponse(
$profile_markup,
$profile,
array(
'title' => $project->getName(),
));
));
}
private function renderBasicInformation($project, $profile) {
$blurb = nonempty(
$profile->getBlurb(),
'//Nothing is known about this elusive project.//');
$factory = new DifferentialMarkupEngineFactory();
$engine = $factory->newDifferentialCommentMarkupEngine();
$blurb = $engine->markupText($blurb);
$affiliations = $project->loadAffiliations();
$phids = array_merge(
array($project->getAuthorPHID()),
mpull($affiliations, 'getUserPHID'));
$handles = id(new PhabricatorObjectHandleData($phids))
->loadHandles();
$affiliated = array();
foreach ($affiliations as $affiliation) {
$user = $handles[$affiliation->getUserPHID()]->renderLink();
$role = phutil_escape_html($affiliation->getRole());
$status = null;
if ($affiliation->getStatus() == 'former') {
$role = '<em>Former '.$role.'</em>';
}
$affiliated[] = '<li>'.$user.' &mdash; '.$role.$status.'</li>';
}
if ($affiliated) {
$affiliated = '<ul>'.implode("\n", $affiliated).'</ul>';
} else {
$affiliated = '<p><em>No one is affiliated with this project.</em></p>';
}
$timestamp = phabricator_format_timestamp($project->getDateCreated());
$status = PhabricatorProjectStatus::getNameForStatus(
$project->getStatus());
$content =
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Basic Information</h1>
<div class="phabricator-profile-info-pane">
<table class="phabricator-profile-info-table">
<tr>
<th>Creator</th>
<td>'.$handles[$project->getAuthorPHID()]->renderLink().'</td>
</tr>
<tr>
<th>Status</th>
<td><strong>'.phutil_escape_html($status).'</strong></td>
</tr>
<tr>
<th>Created</th>
<td>'.$timestamp.'</td>
</tr>
<tr>
<th>PHID</th>
<td>'.phutil_escape_html($project->getPHID()).'</td>
</tr>
<tr>
<th>Blurb</th>
<td>'.$blurb.'</td>
</tr>
</table>
</div>
</div>';
$content .=
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Resources</h1>
<div class="phabricator-profile-info-pane">'.
$affiliated.
'</div>
</div>';
return $content;
}
}

View file

@ -10,11 +10,11 @@ phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'applications/differential/parser/markup');
phutil_require_module('phabricator', 'applications/files/uri');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/controller/base');
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
phutil_require_module('phabricator', 'applications/project/storage/profile');
phutil_require_module('phabricator', 'applications/project/storage/project');
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/layout/profile');
phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');

View file

@ -16,7 +16,7 @@
* limitations under the License.
*/
class PhabricatorProjectEditController
class PhabricatorProjectProfileEditController
extends PhabricatorProjectController {
private $id;
@ -35,9 +35,7 @@ class PhabricatorProjectEditController
if (!$project) {
return new Aphront404Response();
}
$profile = id(new PhabricatorProjectProfile())->loadOneWhere(
'projectPHID = %s',
$project->getPHID());
$profile = $project->getProfile();
} else {
$project = new PhabricatorProject();
$project->setAuthorPHID($user->getPHID());
@ -47,12 +45,13 @@ class PhabricatorProjectEditController
$profile = new PhabricatorProjectProfile();
}
$options = PhabricatorProjectStatus::getStatusMap();
$e_name = true;
$errors = array();
if ($request->isFormPost()) {
$project->setName($request->getStr('name'));
$project->setStatus($request->getStr('status'));
$profile->setBlurb($request->getStr('blurb'));
if (!strlen($project->getName())) {
@ -62,6 +61,21 @@ class PhabricatorProjectEditController
$e_name = null;
}
if (!empty($_FILES['image'])) {
$err = idx($_FILES['image'], 'error');
if ($err != UPLOAD_ERR_NO_FILE) {
$file = PhabricatorFile::newFromPHPUpload($_FILES['image']);
$okay = $file->isTransformableImage();
if ($okay) {
$profile->setProfileImagePHID($file->getPHID());
} else {
$errors[] =
'Only valid image files (jpg, jpeg, png or gif) '.
'will be accepted.';
}
}
}
if (!$errors) {
$project->save();
$profile->setProjectPHID($project->getPHID());
@ -92,20 +106,32 @@ class PhabricatorProjectEditController
$form
->setUser($user)
->setAction($action)
->setEncType('multipart/form-data')
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Name')
->setName('name')
->setValue($project->getName())
->setError($e_name))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel('Project Status')
->setName('status')
->setOptions($options)
->setValue($project->getStatus()))
->appendChild(
id(new AphrontFormTextAreaControl())
->setLabel('Blurb')
->setName('blurb')
->setValue($profile->getBlurb()))
->appendChild(
id(new AphrontFormFileControl())
->setLabel('Change Image')
->setName('image')
->setCaption('Upload a 280px-wide image.'))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton('/project/')
->addCancelButton('/project/view/'.$project->getID().'/')
->setValue('Save'));
$panel = new AphrontPanelView();
@ -122,5 +148,4 @@ class PhabricatorProjectEditController
'title' => $title,
));
}
}

View file

@ -8,10 +8,14 @@
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/files/storage/file');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/controller/base');
phutil_require_module('phabricator', 'applications/project/storage/profile');
phutil_require_module('phabricator', 'applications/project/storage/project');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/file');
phutil_require_module('phabricator', 'view/form/control/select');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/control/text');
phutil_require_module('phabricator', 'view/form/control/textarea');
@ -21,4 +25,4 @@ phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorProjectEditController.php');
phutil_require_source('PhabricatorProjectProfileEditController.php');

View file

@ -28,10 +28,10 @@ class PhabricatorProjectQuickCreateController
$project = new PhabricatorProject();
$project->setAuthorPHID($user->getPHID());
$profile = new PhabricatorProjectProfile();
$options = PhabricatorProjectStatus::getStatusMap();
$e_name = true;
$errors = array();
if ($request->isFormPost()) {
$project->setName($request->getStr('name'));
@ -46,7 +46,6 @@ class PhabricatorProjectQuickCreateController
if (!$errors) {
$project->save();
$profile->setProjectPHID($project->getPHID());
$profile->save();
@ -91,5 +90,4 @@ class PhabricatorProjectQuickCreateController
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}

View file

@ -8,6 +8,7 @@
phutil_require_module('phabricator', 'aphront/response/ajax');
phutil_require_module('phabricator', 'aphront/response/dialog');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/controller/base');
phutil_require_module('phabricator', 'applications/project/storage/profile');
phutil_require_module('phabricator', 'applications/project/storage/project');

View file

@ -23,12 +23,8 @@ class PhabricatorProjectProfile extends PhabricatorProjectDAO {
protected $profileImagePHID;
public function getProfileImagePHID() {
if ($this->profileImagePHID) {
return $this->profileImagePHID;
}
// TODO: Make a separate one of these for projects.
return PhabricatorEnv::getEnvConfig('user.default-profile-image-phid');
return nonempty(
$this->profileImagePHID,
PhabricatorEnv::getEnvConfig('user.default-profile-image-phid'));
}
}

View file

@ -9,5 +9,7 @@
phutil_require_module('phabricator', 'applications/project/storage/base');
phutil_require_module('phabricator', 'infrastructure/env');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorProjectProfile.php');

View file

@ -20,6 +20,7 @@ class PhabricatorProject extends PhabricatorProjectDAO {
protected $name;
protected $phid;
protected $status = PhabricatorProjectStatus::UNKNOWN;
protected $authorPHID;
public function getConfiguration() {
@ -33,4 +34,17 @@ class PhabricatorProject extends PhabricatorProjectDAO {
PhabricatorPHIDConstants::PHID_TYPE_PROJ);
}
public function getProfile() {
$profile = id(new PhabricatorProjectProfile())->loadOneWhere(
'projectPHID = %s',
$this->getPHID());
return $profile;
}
public function loadAffiliations() {
$affiliations = id(new PhabricatorProjectAffiliation())->loadAllWhere(
'projectPHID = %s ORDER BY IF(status = "former", 1, 0), dateCreated',
$this->getPHID());
return $affiliations;
}
}

View file

@ -8,7 +8,12 @@
phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
phutil_require_module('phabricator', 'applications/project/storage/base');
phutil_require_module('phabricator', 'applications/project/storage/profile');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorProject.php');

View file

@ -0,0 +1,55 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorProjectTransactionSearch {
private $projectPhids;
private $documents;
private $status;
public function __construct($project_phids) {
if (is_array($project_phids)) {
$this->projectPhids = $project_phids;
} else {
$this->projectPhids = array($project_phids);
}
return $this;
}
// search all open documents by default
public function setSearchOptions($documents = '', $status = true) {
$this->documents = $documents;
$this->status = $status;
return $this;
}
public function executeSearch() {
$projects = $this->projectPhids;
$on_documents = $this->documents;
$with_status = $this->status;
$query = new PhabricatorSearchQuery();
$query->setQuery('');
$query->setParameter('project', $projects);
$query->setParameter('type', $on_documents);
$query->setParameter('open', $with_status);
$executor = new PhabricatorSearchMySQLExecutor();
$results = $executor->executeSearch($query);
return $results;
}
}

View file

@ -0,0 +1,13 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'applications/search/execute/mysql');
phutil_require_module('phabricator', 'applications/search/storage/query');
phutil_require_source('PhabricatorProjectTransactionSearch.php');

View file

@ -0,0 +1,93 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class PhabricatorProfileView extends AphrontView {
protected $items = array();
protected $profilePicture;
protected $profileName;
protected $profileRealname;
protected $profileTitle;
public function addProfileItem($item) {
$this->items[] = $item;
return $this;
}
public function setProfilePicture($picture) {
$this->profilePicture = $picture;
return $this;
}
public function setProfileNames($name, $realname = null, $title = null) {
$this->profileName = $name;
$this->profileRealname = $realname;
$this->profileTitle = $title;
return $this;
}
public function render() {
$view = new AphrontNullView();
$view->appendChild($this->items);
$side_links = null;
$realname = null;
$title = null;
if (!empty($this->profileRealname)) {
$realname =
'<h2 class="phabricator-profile-realname">'.
phutil_escape_html($this->profileRealname).
'</h2>';
}
if (!empty($this->profileTitle)) {
$title =
'<h2>'.
phutil_escape_html($this->profileTitle).
'</h2>';
}
if (!empty($this->items)) {
$side_links =
$view->render().
'<hr />';
}
require_celerity_resource('phabricator-profile-css');
return
'<table class="phabricator-profile-master-layout">'.
'<tr>'.
'<td class="phabricator-profile-navigation">'.
'<h1>'.phutil_escape_html($this->profileName).'</h1>'.
$realname.
$title.
'<hr />'.
'<img class="phabricator-profile-image" src="'.
$this->profilePicture.
'"/>'.
'<hr />'.
$side_links.
'</td>'.
'<td class="phabricator-profile-content">'.
$this->renderChildren().
'</td>'.
'</tr>'.
'</table>';
}
}

View file

@ -0,0 +1,16 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/base');
phutil_require_module('phabricator', 'view/null');
phutil_require_module('phutil', 'markup');
phutil_require_source('PhabricatorProfileView.php');

View file

@ -2,20 +2,72 @@
* @provides phabricator-profile-css
*/
.phabricator-profile-master-layout {
table.phabricator-profile-master-layout {
width: 100%;
}
.phabricator-profile-navigation {
td.phabricator-profile-navigation {
width: 300px;
background: #efefef;
border-right: 1px solid #cccccc;
padding-top: 8px;
padding-bottom: 8em;
}
.phabricator-profile-content {
td.phabricator-profile-navigation a,
td.phabricator-profile-navigation span {
display: block;
margin: 0 0 2px;
min-width: 150px;
font-weight: bold;
white-space: nowrap;
text-decoration: none;
}
td.phabricator-profile-navigation a {
padding: 4px 8px 4px 10px;
}
td.phabricator-profile-navigation a:hover {
text-decoration: none;
background: #cccccc;
}
td.phabricator-profile-navigation a.phabricator-profile-item-selected,
td.phabricator-profile-navigation a.phabricator-profile-item-selected :hover {
background: #cccccc;
}
td.phabricator-profile-navigation hr {
border: none;
background: #cccccc;
padding: 0;
margin: 10px 0;
height: 1px;
}
td.phabricator-profile-navigation h1,
td.phabricator-profile-navigation h2 {
padding: 2px 0px 0px 10px;
}
td.phabricator-profile-content {
padding: 2em 2%;
}
.phabricator-profile-info-table th {
font-weight: bold;
text-align: right;
color: #666666;
width: 10%;
padding: 4px;
}
.phabricator-profile-info-table td {
width: 100%;
padding: 4px;
}
.phabricator-profile-info-group {
margin-bottom: 2em;
background: #efefef;
@ -35,52 +87,11 @@
width: 100%;
}
.phabricator-profile-info-table th {
font-weight: bold;
text-align: right;
color: #666666;
width: 10%;
padding: 4px;
}
.phabricator-profile-info-table td {
width: 100%;
padding: 4px;
}
.phabricator-profile-navigation hr {
border: none;
background: #cccccc;
padding: 0;
margin: 10px 0;
height: 1px;
}
.phabricator-profile-navigation {
padding-top: 8px;
padding-bottom: 8em;
}
.phabricator-profile-navigation h1,
.phabricator-profile-navigation h2 {
padding: 2px 8px;
}
h2.profile-realname {
h2.phabricator-profile-realname {
color: #666666;
}
img.profile-image {
img.phabricator-profile-image {
width: 280px;
margin: 10px;
}
ul.profile-nav-links li a {
display: block;
padding: 4px 8px 4px 12px;
font-weight: bold;
}
ul.profile-nav-links li a:hover {
background: #cccccc;
}