Page MenuHomec4science

PhabricatorC4sHome.php
No OneTemporary

File Metadata

Created
Wed, May 1, 11:30

PhabricatorC4sHome.php

<?php
final class PhabricatorC4sHome
extends PhabricatorHomeController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $request->getViewer();
if($request->getPath() == '/home/render/feed') {
require_celerity_resource('phabricator-dashboard-css');
$content = $this->getFeedContent($request);
return id(new AphrontAjaxResponse())
->setContent(array(
'panelMarkup' => hsprintf('%s', $content),
));
} else if(!$viewer->getUsername() || $request->getPath() == '/public') {
$view = $this->publicPage($request, $viewer);
} else {
$view = $this->userPage($request, $viewer);
}
$navigation = $this->buildSideNavView($request);
$page = $this->newPage()
->setNavigation($navigation)
->appendChild($view);
// On mobile, / is the menu and /home is the content
$is_content = $request->getURIData('content');
if (!$is_content) {
$page->addClass('phabricator-home');
}
return $page;
}
private function userPage($request, $viewer) {
$tab_key = $request->getStr('tab');
$order_key = $request->getStr('order', 'committed');
// Get and check order key
$repo_order = id(new PhabricatorRepositoryQuery())
->getBuiltinOrders();
unset($repo_order['callsign']); //FIXME: for some reason, ordering with
// the calllsign field doesn't work
// and crashes, not very usefull though
if(!in_array($order_key, array_keys($repo_order))) {
$order_key = 'committed';
}
// My repo tab (can_edit + created)
$view_my = $this->buildRepositoryPanel(
$request, 'my', null, 10, false, $order_key, 'author');
$tab_my = id(new PHUITabView())
->setName(pht('Your repositories'))
->setKey('my')
->appendChild($view_my);
// Contribution tab (can_push)
$view_contrib = $this->buildRepositoryPanel(
$request, 'contrib', null, 10, false, $order_key, 'contrib');
$tab_contrib = id(new PHUITabView())
->setName(pht('Contribution'))
->setKey('contrib')
->appendChild($view_contrib);
// Tab Repositories
$tab_group_repo = id(new PHUITabGroupView())
->addTab($tab_my)
->addTab($tab_contrib);
if(in_array($tab_key, array('my', 'contrib'))) {
$tab_group_repo->selectTab($tab_key);
}
// Box header
$actions = id(new PhabricatorActionListView())
->setViewer($viewer);
foreach($repo_order as $orderKey => $orderValue) {
$action = id(new PhabricatorActionView())
->setName($orderValue['name'])
->setHref('?order=' . $orderKey . '#box_repo');
if($order_key == $orderKey) {
$action->setSelected(true);
}
$actions->addAction($action);
}
$order_link = id(new PHUIButtonView())
->setText('Order By: ' . $order_key)
->setTag('a')
->setIcon('fa-sort')
->setDropdown(true)
->setDropdownMenu($actions);
$header = id(new PHUIHeaderView())
->setHeader(pht('Repositories'))
->addActionLink($order_link);
// Box
$anchor = id(new PhabricatorAnchorView())
->setAnchorName('box_repo');
$tab_repo = id(new PHUIObjectBoxView())
->setHeader($header)
->setAnchor($anchor)
->addTabGroup($tab_group_repo);
// Projects member
$view_member = $this->buildProjectsPanel($request, 'member', 'member');
$tab_member = id(new PHUITabView())
->setName(pht('Member'))
->setKey('member')
->appendChild($view_member);
// Projects watcher
$view_watcher = $this->buildProjectsPanel($request, 'watcher', 'watcher');
$tab_watcher = id(new PHUITabView())
->setName(pht('Watcher'))
->setKey('watcher')
->appendChild($view_watcher);
// Tab Projects
$tab_group_proj = id(new PHUITabGroupView())
->addTab($tab_member)
->addTab($tab_watcher);
if(in_array($tab_key, array('member', 'watcher'))) {
$tab_group_proj->selectTab($tab_key);
}
$anchor = id(new PhabricatorAnchorView())
->setAnchorName('box_proj');
$tab_proj = id(new PHUIObjectBoxView())
->setHeaderText('Projects')
->setAnchor($anchor)
->addTabGroup($tab_group_proj);
// Columns
$col_repo = phutil_tag(
'div',
array(
'class' => 'homepage-panel',
),
array(
$tab_repo,
$tab_proj,
));
$col_feed = phutil_tag(
'div',
array(
'class' => 'homepage-panel',
),
array(
//$this->buildShortcuts(),
$this->buildAnnouncement(),
$this->buildFeedPanel($request, false),
));
$view = id(new AphrontMultiColumnView())
->addColumn($col_repo)
->addColumn($col_feed)
->setFluidLayout(true);
return $view;
}
private function publicPage($request, $viewer) {
$col_feed = phutil_tag(
'div',
array(
'class' => 'homepage-panel',
),
array(
$this->buildAnnouncement(),
$this->buildFeedPanel($request),
));
$view_active = $this->buildRepositoryPanel($request, 'active', null, 10);
$tab_active = id(new PHUITabView())
->setName(pht('Recently Active'))
->setKey('active')
->appendChild($view_active);
$view_commits = $this->buildRepositoryPanel($request, 'commits', null, 10, true, 'size');
$tab_commits = id(new PHUITabView())
->setName(pht('Most commits'))
->setKey('commits')
->appendChild($view_commits);
$view_users = $this->buildRepositoryPanel($request, 'users', null, 10, true, 'users');
$tab_users = id(new PHUITabView())
->setName(pht('Most contributors'))
->setKey('users')
->appendChild($view_users);
$tab_group = id(new PHUITabGroupView())
->addTab($tab_active)
->addTab($tab_commits)
->addTab($tab_users);
$tab_key = $request->getStr('tab');
if(in_array($tab_key, array('my', 'contrib'))) {
$tab_group->selectTab($tab_key);
}
$anchor = id(new PhabricatorAnchorView())
->setAnchorName('box_repo');
$tab_view = id(new PHUIObjectBoxView())
->setHeaderText('Repositories')
->setAnchor($anchor)
->addTabGroup($tab_group);
$col_repo = phutil_tag(
'div',
array(
'class' => 'homepage-panel',
),
array(
$this->buildPresentationPanel(),
$tab_view,
));
$view = id(new AphrontMultiColumnView())
->addColumn($col_repo)
->addColumn($col_feed)
->setFluidLayout(true);
return $view;
}
private function buildAnnouncement() {
$viewer = $this->getViewer();
$dashboard = id(new PhabricatorDashboard())
->loadOneWhere('name = "Service Announcement" && editPolicy = "admin"');
if(!$dashboard) {
return;
}
$dashboard = id(new PhabricatorDashboardQuery())
->setViewer($viewer)
->withPHIDs(array($dashboard->getPHID()))
->needPanels(true)
->executeOne();
if(!$dashboard->getPanelPHIDs()) {
return;
}
$panels = id(new PhabricatorDashboardPanelQuery())
->setViewer($viewer)
->withPHIDs($dashboard->getPanelPHIDs())
->execute();
$boxes = array();
foreach($panels as $panel) {
if($panel->getPanelType() != 'text') {
continue;
}
$remarkup = new PHUIRemarkupView($viewer, $panel->getProperty('text'));
$layout = id(new PHUIBoxView())
->appendChild($remarkup)
->addMargin(PHUI::MARGIN_MEDIUM);
$boxes[] = id(new PHUIObjectBoxView())
->setHeaderText($panel->getName())
->appendChild($layout);
}
return $boxes;
}
private function buildShortcuts() {
$icons = array(
id(new PHUIIconView())
->setIcon('fa-briefcase')
->setBackground('bg-grey')
->setTooltip('Create Project')
->addClass('mmr')
->setHref('/project/edit/form/default/'),
id(new PHUIIconView())
->setIcon('fa-code')
->setBackground('bg-grey')
->setTooltip('Create Repository')
->addClass('mmr')
->setHref('/diffusion/edit/form/default/'),
id(new PHUIIconView())
->setIcon('fa-bug')
->setBackground('bg-grey')
->setTooltip('Report a bug')
->addClass('mmr')
->setHref('/maniphest/task/edit/form/8/'),
id(new PHUIIconView())
->setIcon('fa-book')
->setBackground('bg-grey')
->setTooltip('Documentation')
->addClass('mmr')
->setHref('/w/c4science')
);
$layout = id(new PHUIBoxView())
->appendChild($icons)
->addMargin(PHUI::MARGIN_MEDIUM);
$box = id(new PHUIObjectBoxView())
->setHeaderText('Shortcuts')
->appendChild($layout);
return $box;
}
private function getFeedContent($request) {
// hack to have global in the request
$global = $request->getBool('dashboardID', true);
$viewer = $this->getViewer();
$phids = array();
$epoch_min = time() - 7*24*3600; // 7 days
$epoch_max = time();
if(!$global) {
//User
$phids += array($viewer->getPHID());
// Projects
$projects = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->withMemberPHIDs(array($viewer->getPHID()))
->execute();
$project_phids = mpull($projects, 'getPHID');
$phids += array_fuse($project_phids);
// Repositories (created by user)
$repo_transaction = id(new PhabricatorRepositoryTransactionQuery())
->setViewer($viewer)
->withAuthorPHIDs(array($viewer->getPHID()))
->withTransactionTypes(array(PhabricatorTransactions::TYPE_CREATE))
->needComments(false)
->needHandles(false)
->execute();
$repo = array_fuse(mpull($repo_transaction, 'getObjectPHID'));
// Repositories (in project user is member of)
if(!empty($projects)) {
$any = array();
foreach($project_phids as $phid) {
$any[] = 'any(' . $phid . ')';
}
$datasource = id(new PhabricatorProjectLogicalDatasource())
->setViewer($viewer);
$constraints = $datasource->evaluateTokens($any);
$query = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->withEdgeLogicConstraints(
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST,
$constraints)
->execute();
$repo += array_fuse(mpull($query, 'getPHID'));
}
// Commits for selected Repositories
if(!empty($repo)) {
$commits = id(new DiffusionCommitQuery())
->setViewer($viewer)
->withRepositoryPHIDs($repo)
->withEpochRange($epoch_min, $epoch_max)
->execute();
$phids += array_fuse(mpull($commits, 'getPHID'));
}
// Phriction pages
if(!empty($projects)) {
$slugs = array();
foreach($projects as $p) {
$slugs[] = PhabricatorProjectWikiCreate::getAllSlugs($p);
}
$wiki = id(new PhrictionDocumentQuery())
->setViewer($viewer)
->withSlugsPrefix($slugs)
->withStatus(PhrictionDocumentQuery::STATUS_OPEN)
->execute();
$phids += array_fuse(mpull($wiki, 'getPHID'));
}
}
// Build Feed stories
$stories = id(new PhabricatorFeedQuery())
->setViewer($viewer)
->withFilterPHIDs($phids)
->withEpochInRange($epoch_min, $epoch_max)
->setLimit(12)
->execute();
$view = id(new PhabricatorFeedBuilder($stories))
->setUser($viewer)
->buildView();
return $view;
}
private function buildFeedPanel($request, $global=true) {
$panel_id = celerity_generate_unique_node_id();
Javelin::initBehavior(
'dashboard-async-panel',
array(
'panelID' => $panel_id,
'parentPanelPHIDs' => array(),
'headerMode' => 'none',
'dashboardID' => $global,
'uri' => '/home/render/feed',
));
$view_all = id(new PHUIButtonView())
->setTag('a')
->setIcon(id(new PHUIIconView())->setIcon('fa-list-ul'))
->setText(pht('View All'))
->setHref('/feed/');
$header = id(new PHUIHeaderView())
->setHeader(pht('Recent Activity'))
->addActionLink($view_all);
$feed_box = id(new PHUIBoxView())
->setID($panel_id)
->addPadding(PHUI::PADDING_LARGE)
->appendChild(pht('Loading...'));
$feed = id(new PHUIObjectBoxView())
->setHeader($header)
->appendChild($feed_box);
return $feed;
}
private function buildProjectsPanel($request, $tab_key, $filter='member', $proj_count=10) {
$viewer = $this->getViewer();
$pager = id(new AphrontCursorPagerView())
->setURI(new PhutilURI('?tab=' . $tab_key . '#box_proj'))
->setPageSize($proj_count);
if($tab_key == $request->getStr('tab') &&
in_array($tab_key, array('member', 'watcher'))) {
$pager
->setAfterID($request->getStr('after'))
->setBeforeID($request->getStr('before'));
}
$projects = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->setOrder('newest')
->needImages(true)
->withStatuses(array(PhabricatorProjectStatus::STATUS_ACTIVE));
if($filter == 'member') {
$projects->withMemberPHIDs(array($viewer->getPHID()));
} else if($filter == 'watcher') {
$projects->withWatcherPHIDs(array($viewer->getPHID()));
}
$projects = $projects->executeWithCursorPager($pager);
if (!empty($projects)) {
$list = id(new PhabricatorProjectListView())
->setUser($viewer)
->setProjects($projects);
} else {
if($filter == 'member') {
$str = 'No project found. [[/project/edit/form/default/ | Create a new project]].';
} else if($filter == 'watcher') {
$str = 'No project found. [[/project/query/active/ | Watch a project]].';
}
$remarkup = new PHUIRemarkupView($viewer, $str);
$list = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_LARGE)
->appendChild($remarkup);
}
$box = id(new PHUIObjectBoxView())
->appendChild($list);
if($pager->willShowPagingControls()) {
$box->appendChild($pager);
}
return $box;
}
private function buildRepositoryPanel(
$request,
$tab_key,
$title,
$repo_count=5,
$compact=false,
$order='committed',
$filter=null)
{
$viewer = $this->getViewer();
$pager = id(new AphrontCursorPagerView())
->setURI(new PhutilURI('?tab=' . $tab_key . '&order=' . $order . '#box_repo'))
->setPageSize($repo_count);
if($tab_key == $request->getStr('tab') &&
in_array($tab_key, array('my', 'contrib'))) {
$pager
->setAfterID($request->getStr('after'))
->setBeforeID($request->getStr('before'));
}
// Get repositories
if($order == 'users') {
$table = id(new PhabricatorRepositoryCommit());
$repo = queryfx_all(
$table->establishConnection('r'),
'SELECT a.name, a.rid, count(*) AS cnt, a.phid FROM
(SELECT r.phid as phid, r.name AS name, repositoryID AS rid, authorPHID AS aid
FROM repository_commit JOIN repository AS r ON r.id=repositoryID
WHERE viewPolicy="public" AND authorPHID IS NOT NULL AND importStatus=15
GROUP BY aid)a GROUP BY a.rid ORDER BY cnt DESC LIMIT %d',
$repo_count);
} else {
$repo = id(new PhabricatorRepositoryQuery())
->setViewer($viewer)
->setOrder($order)
->needCommitCounts(true);
if(!$compact) {
$repo
->needMostRecentCommits(true)
->needProjectPHIDs(true)
->needProfileImage(true);
}
if($filter == 'contrib') {
$repo->requireCapabilities(array(DiffusionPushCapability::CAPABILITY));
$repo->withCanPush();
}
if($filter == 'author') {
$repo->withAuthors(array($viewer->getPHID()));
} else if($viewer->getUsername()) {
$repo->withoutAuthors(array($viewer->getPHID()));
}
$repo = $repo->executeWithCursorPager($pager);
}
// Create List
if(!empty($repo)) {
$list = new PHUIObjectItemListView();
} else {
$remarkup = new PHUIRemarkupView($viewer,
'No repository found. [[/diffusion/edit/form/default/ | Create a new repository]].');
$list = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_LARGE)
->appendChild($remarkup);
}
foreach($repo as $r){
$item = id(new PHUIObjectItemView());
if($order == 'users') {
$item
->setHeader($r['name'])
->addIcon('', pht('%s Users', new PhutilNumber($r['cnt'])))
->setHref(pht('/diffusion/%d/', $r['rid']));
} else {
if($r->getStatus() == PhabricatorRepository::STATUS_INACTIVE) {
$item->setDisabled(true);
}
$item
->setHeader($r->getName())
->addIcon('', pht('%s Commit(s)', new PhutilNumber($r->getCommitCount())))
->setHref($r->getURI());
}
if(!$compact) {
$item->setImageURI($r->getProfileImageURI());
$desc = id(new PhutilUTF8StringTruncator())
->setMaximumGlyphs(120)
->truncateString($r->getDetail('description'));
$desc = new PHUIRemarkupView($viewer, $desc);
$item->setSubHead($desc);
if($r->getMostRecentCommit()) {
$item->addIcon('',
phabricator_date(
$r->getMostRecentCommit()->getDateCreated(),
$viewer));
}
if($r->getProjectPHIDs()) {
$handles = id(new PhabricatorHandleQuery())
->setViewer($viewer)
->witHPHIDs($r->getProjectPHIDs())
->execute();
$project_handles = array_select_keys(
$handles,
$r->getProjectPHIDs());
if ($project_handles) {
$item->addAttribute(
id(new PHUIHandleTagListView())
->setSlim(true)
->setHandles($project_handles));
}
}
}
$list->addItem($item);
}
if($pager->willShowPagingControls()) {
$pager_item = id(new PHUIObjectItemView())
->appendChild($pager);
$list->addItem($pager_item);
}
$box = id(new PHUIObjectBoxView())
->setObjectList($list);
if($title) {
$header = id(new PHUIHeaderView())
->setHeader($title);
$box->setHeader($header);
}
if($order == 'users') {
$repo_phids = ipull($repo, 'phid');
} else {
$repo_phids = mpull($repo, 'getPHID');
}
return $box;
}
private function buildPresentationPanel() {
$viewer = $this->getViewer();
$content = pht(<<<EOF
## c4science.ch
Infrastructure for scientific code co-creation, curation, sharing and testing. Available to the entire Swiss universities community and accessible to external collaborators.
Hosted on [[https://www.switch.ch/engines/ | SWITCHengines]], managed by [[http://scitas.epfl.ch/ | EPFL-SCITAS]], created via [[https://www.science-it.ch/ | eSCT]], a [[https://www.swissuniversities.ch/ | Swissuniversities]] funded project.
## {icon sign-in} Login
[[ /auth/start/ | Login ]] with SwitchAAI (for Swiss universities), Google, Github or local account.
EOF
);
$remarkup = new PHUIRemarkupView($viewer, $content);
$box = id(new PHUIObjectBoxView())
->appendChild($remarkup);
return $box;
}
private function buildSideNavView(AphrontRequest $request) {
$viewer = $this->getViewer();
$home = id(new PhabricatorHomeApplication());
$engine = id(new PhabricatorHomeProfileMenuEngine())
->setViewer($viewer)
->setProfileObject($home)
->setCustomPHID($viewer->getPHID());
$is_content = $request->getURIData('content');
if (!$is_content) {
$engine->addContentPageClass('phabricator-home');
}
return $engine->buildNavigation();
}
}

Event Timeline