diff --git a/resources/sql/patches/047.projectstatus.sql b/resources/sql/patches/047.projectstatus.sql new file mode 100644 index 0000000000..5b3e843018 --- /dev/null +++ b/resources/sql/patches/047.projectstatus.sql @@ -0,0 +1,2 @@ +ALTER TABLE phabricator_project.project + ADD status varchar(32) not null; \ No newline at end of file diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 01ec3fbaca..dd5008b80a 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -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( diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index e42980f2c9..6961bbe47a 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -422,16 +422,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', @@ -887,15 +890,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', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index 945ca3cf34..42ff0a847c 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -76,7 +76,8 @@ class AphrontDefaultApplicationConfiguration 'edit/(?:(?P\d+)/(?:(?P\w+)/)?)?$' => 'PhabricatorPeopleEditController', ), - '/p/(?P\w+)/$' => 'PhabricatorPeopleProfileController', + '/p/(?P\w+)/(?:(?P\w+)/)?$' + => 'PhabricatorPeopleProfileController', '/profile/' => array( 'edit/$' => 'PhabricatorPeopleProfileEditController', ), @@ -197,8 +198,9 @@ class AphrontDefaultApplicationConfiguration '/project/' => array( '$' => 'PhabricatorProjectListController', - 'edit/(?:(?P\d+)/)?$' => 'PhabricatorProjectEditController', - 'view/(?P\d+)/$' => 'PhabricatorProjectProfileController', + 'edit/(?:(?P\d+)/)?$' => 'PhabricatorProjectProfileEditController', + 'view/(?P\d+)/(?:(?P\w+)/)?$' + => 'PhabricatorProjectProfileController', 'affiliation/(?P\d+)/$' => 'PhabricatorProjectAffiliationEditController', 'quickcreate/$' => 'PhabricatorProjectQuickCreateController', diff --git a/src/applications/people/controller/profile/PhabricatorPeopleProfileController.php b/src/applications/people/controller/profile/PhabricatorPeopleProfileController.php index c27efd9ba7..8c6d68ab5e 100644 --- a/src/applications/people/controller/profile/PhabricatorPeopleProfileController.php +++ b/src/applications/people/controller/profile/PhabricatorPeopleProfileController.php @@ -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] = '
  • '.$link.'
  • '; + // 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 = - ''; - $title = nonempty($profile->getTitle(), 'Untitled Document'); - - $username_tag = - '

    '. - phutil_escape_html($user->getUserName()). - '

    '; - $realname_tag = - '

    '. - '('.phutil_escape_html($user->getRealName()).')'. - '

    '; - $title_tag = - '

    '. - phutil_escape_html($title). - '

    '; + 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 { '; - $profile = - ' - - - - -
    '. - $username_tag. - $realname_tag. - $title_tag. - '
    '. - $picture. - '
    '. - $links. - '
    '. - '
    '. - $content. - '
    '; - - return $this->buildStandardPageResponse( - $profile, - array( - 'title' => $user->getUsername(), - )); + return $content; } - } diff --git a/src/applications/people/controller/profile/__init__.php b/src/applications/people/controller/profile/__init__.php index e336f1b0c1..005d726611 100644 --- a/src/applications/people/controller/profile/__init__.php +++ b/src/applications/people/controller/profile/__init__.php @@ -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'); diff --git a/src/applications/people/controller/profileedit/PhabricatorPeopleProfileEditController.php b/src/applications/people/controller/profileedit/PhabricatorPeopleProfileEditController.php index cd4d1d1620..5b7ec23d31 100644 --- a/src/applications/people/controller/profileedit/PhabricatorPeopleProfileEditController.php +++ b/src/applications/people/controller/profileedit/PhabricatorPeopleProfileEditController.php @@ -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 )); } -} \ No newline at end of file +} diff --git a/src/applications/project/constants/status/PhabricatorProjectStatus.php b/src/applications/project/constants/status/PhabricatorProjectStatus.php new file mode 100644 index 0000000000..d933249636 --- /dev/null +++ b/src/applications/project/constants/status/PhabricatorProjectStatus.php @@ -0,0 +1,58 @@ + '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', + ); + } +} diff --git a/src/applications/project/constants/status/__init__.php b/src/applications/project/constants/status/__init__.php new file mode 100644 index 0000000000..03ed2bb35a --- /dev/null +++ b/src/applications/project/constants/status/__init__.php @@ -0,0 +1,12 @@ +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; + } + } } diff --git a/src/applications/project/controller/list/__init__.php b/src/applications/project/controller/list/__init__.php index aff05271b4..72b8bf175b 100644 --- a/src/applications/project/controller/list/__init__.php +++ b/src/applications/project/controller/list/__init__.php @@ -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'); diff --git a/src/applications/project/controller/profile/PhabricatorProjectProfileController.php b/src/applications/project/controller/profile/PhabricatorProjectProfileController.php index 451601c4be..ace47f9f27 100644 --- a/src/applications/project/controller/profile/PhabricatorProjectProfileController.php +++ b/src/applications/project/controller/profile/PhabricatorProjectProfileController.php @@ -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( + /* + '

    Active Documents

    ', + 'tasks' => 'Maniphest Tasks', + 'revisions' => 'Differential Revisions', + '
    ', + '

    Workflow

    ', + 'goals' => 'Goals', + 'statistics' => 'Statistics', + '
    ', */ + '

    Information

    ', + 'edit' => 'Edit Profile', + 'affiliation' => 'Edit Affiliation', + ); - $links = - ''; + 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 = 'Former '.$role.''; + $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[] = '
  • '.$user.' — '.$role.$status.'
  • '; - } - if ($affiliated) { - $affiliated = '
      '.implode("\n", $affiliated).'
    '; - } else { - $affiliated = '

    No one is affiliated with this project.

    '; } - $timestamp = phabricator_format_timestamp($project->getDateCreated()); - - $content = - '
    -

    Basic Information

    -
    - - - - - - - - - - - - - - - - - -
    Creator'.$handles[$project->getAuthorPHID()]->renderLink().'
    Created'.$timestamp.'
    PHID'.phutil_escape_html($project->getPHID()).'
    Blurb'.$blurb.'
    -
    -
    '; - - $content .= - '
    -

    Resources

    -
    '. - $affiliated. - '
    -
    '; - - - $profile_markup = - ' - - - - -
    '. - '

    '.phutil_escape_html($project->getName()).'

    '. - '
    '. - $picture. - '
    '. - $links. - '
    '. - '
    '. - $content. - '
    '; + $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 = 'Former '.$role.''; + } + + $affiliated[] = '
  • '.$user.' — '.$role.$status.'
  • '; + } + if ($affiliated) { + $affiliated = '
      '.implode("\n", $affiliated).'
    '; + } else { + $affiliated = '

    No one is affiliated with this project.

    '; + } + + $timestamp = phabricator_format_timestamp($project->getDateCreated()); + $status = PhabricatorProjectStatus::getNameForStatus( + $project->getStatus()); + + $content = + '
    +

    Basic Information

    +
    + + + + + + + + + + + + + + + + + + + + + +
    Creator'.$handles[$project->getAuthorPHID()]->renderLink().'
    Status'.phutil_escape_html($status).'
    Created'.$timestamp.'
    PHID'.phutil_escape_html($project->getPHID()).'
    Blurb'.$blurb.'
    +
    +
    '; + + $content .= + '
    +

    Resources

    +
    '. + $affiliated. + '
    +
    '; + + return $content; + } } diff --git a/src/applications/project/controller/profile/__init__.php b/src/applications/project/controller/profile/__init__.php index d51116a235..b78ed711a8 100644 --- a/src/applications/project/controller/profile/__init__.php +++ b/src/applications/project/controller/profile/__init__.php @@ -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'); diff --git a/src/applications/project/controller/edit/PhabricatorProjectEditController.php b/src/applications/project/controller/profileedit/PhabricatorProjectProfileEditController.php similarity index 72% rename from src/applications/project/controller/edit/PhabricatorProjectEditController.php rename to src/applications/project/controller/profileedit/PhabricatorProjectProfileEditController.php index 2b0dd3b27a..9baeea4818 100644 --- a/src/applications/project/controller/edit/PhabricatorProjectEditController.php +++ b/src/applications/project/controller/profileedit/PhabricatorProjectProfileEditController.php @@ -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, )); } - } diff --git a/src/applications/project/controller/edit/__init__.php b/src/applications/project/controller/profileedit/__init__.php similarity index 71% rename from src/applications/project/controller/edit/__init__.php rename to src/applications/project/controller/profileedit/__init__.php index 9533fc6975..ae3c1e153e 100644 --- a/src/applications/project/controller/edit/__init__.php +++ b/src/applications/project/controller/profileedit/__init__.php @@ -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'); diff --git a/src/applications/project/controller/quickcreate/PhabricatorProjectQuickCreateController.php b/src/applications/project/controller/quickcreate/PhabricatorProjectQuickCreateController.php index 411021ac1d..e4e2c1796e 100644 --- a/src/applications/project/controller/quickcreate/PhabricatorProjectQuickCreateController.php +++ b/src/applications/project/controller/quickcreate/PhabricatorProjectQuickCreateController.php @@ -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); } - } diff --git a/src/applications/project/controller/quickcreate/__init__.php b/src/applications/project/controller/quickcreate/__init__.php index 22b2b9b1b9..3e33f41148 100644 --- a/src/applications/project/controller/quickcreate/__init__.php +++ b/src/applications/project/controller/quickcreate/__init__.php @@ -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'); diff --git a/src/applications/project/storage/profile/PhabricatorProjectProfile.php b/src/applications/project/storage/profile/PhabricatorProjectProfile.php index 1b8b12159f..98df728d5b 100644 --- a/src/applications/project/storage/profile/PhabricatorProjectProfile.php +++ b/src/applications/project/storage/profile/PhabricatorProjectProfile.php @@ -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')); } - - } diff --git a/src/applications/project/storage/profile/__init__.php b/src/applications/project/storage/profile/__init__.php index f7dbfa86e5..7049de11cc 100644 --- a/src/applications/project/storage/profile/__init__.php +++ b/src/applications/project/storage/profile/__init__.php @@ -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'); diff --git a/src/applications/project/storage/project/PhabricatorProject.php b/src/applications/project/storage/project/PhabricatorProject.php index 3064c20207..b8cd85ec28 100644 --- a/src/applications/project/storage/project/PhabricatorProject.php +++ b/src/applications/project/storage/project/PhabricatorProject.php @@ -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; + } } diff --git a/src/applications/project/storage/project/__init__.php b/src/applications/project/storage/project/__init__.php index f378038d02..bc7599691d 100644 --- a/src/applications/project/storage/project/__init__.php +++ b/src/applications/project/storage/project/__init__.php @@ -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'); diff --git a/src/applications/project/transactions/search/PhabricatorProjectTransactionSearch.php b/src/applications/project/transactions/search/PhabricatorProjectTransactionSearch.php new file mode 100644 index 0000000000..02e569c81b --- /dev/null +++ b/src/applications/project/transactions/search/PhabricatorProjectTransactionSearch.php @@ -0,0 +1,55 @@ +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; + } +} diff --git a/src/applications/project/transactions/search/__init__.php b/src/applications/project/transactions/search/__init__.php new file mode 100644 index 0000000000..722f521d91 --- /dev/null +++ b/src/applications/project/transactions/search/__init__.php @@ -0,0 +1,13 @@ +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 = + '

    '. + phutil_escape_html($this->profileRealname). + '

    '; + } + + if (!empty($this->profileTitle)) { + $title = + '

    '. + phutil_escape_html($this->profileTitle). + '

    '; + } + + if (!empty($this->items)) { + $side_links = + $view->render(). + '
    '; + } + + require_celerity_resource('phabricator-profile-css'); + + return + ''. + ''. + ''. + ''. + ''. + '
    '. + '

    '.phutil_escape_html($this->profileName).'

    '. + $realname. + $title. + '
    '. + ''. + '
    '. + $side_links. + '
    '. + $this->renderChildren(). + '
    '; + } +} diff --git a/src/view/layout/profile/__init__.php b/src/view/layout/profile/__init__.php new file mode 100644 index 0000000000..2704866d63 --- /dev/null +++ b/src/view/layout/profile/__init__.php @@ -0,0 +1,16 @@ +