Skip to content

Commit 60466d3

Browse files
committedOct 24, 2012
Create a status tool by giving /calendar/ some teeth
Summary: you can now add, edit, and delete status events. also added a "description" to status events and surface it in the big calendar view on mouse hover. some refactoring changes as well to make validation logic centralized within the storage class. Test Plan: added, edited, deleted. yay. Reviewers: epriestley, vrana Reviewed By: epriestley CC: aran, Korvin Maniphest Tasks: T407 Differential Revision: https://secure.phabricator.com/D3810
1 parent 244b130 commit 60466d3

18 files changed

+718
-80
lines changed
 

‎resources/sql/patches/statustxt.sql

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE {$NAMESPACE}_user.user_status
2+
ADD description LONGTEXT NOT NULL COLLATE utf8_bin;

‎src/__phutil_library_map__.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,7 @@
553553
'PhabricatorApplicationApplications' => 'applications/meta/application/PhabricatorApplicationApplications.php',
554554
'PhabricatorApplicationAudit' => 'applications/audit/application/PhabricatorApplicationAudit.php',
555555
'PhabricatorApplicationAuth' => 'applications/auth/application/PhabricatorApplicationAuth.php',
556+
'PhabricatorApplicationCalendar' => 'applications/calendar/application/PhabricatorApplicationCalendar.php',
556557
'PhabricatorApplicationConduit' => 'applications/conduit/application/PhabricatorApplicationConduit.php',
557558
'PhabricatorApplicationCountdown' => 'applications/countdown/application/PhabricatorApplicationCountdown.php',
558559
'PhabricatorApplicationDaemons' => 'applications/daemon/application/PhabricatorApplicationDaemons.php',
@@ -609,8 +610,11 @@
609610
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php',
610611
'PhabricatorCalendarController' => 'applications/calendar/controller/PhabricatorCalendarController.php',
611612
'PhabricatorCalendarDAO' => 'applications/calendar/storage/PhabricatorCalendarDAO.php',
613+
'PhabricatorCalendarDeleteStatusController' => 'applications/calendar/controller/PhabricatorCalendarDeleteStatusController.php',
614+
'PhabricatorCalendarEditStatusController' => 'applications/calendar/controller/PhabricatorCalendarEditStatusController.php',
612615
'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php',
613616
'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php',
617+
'PhabricatorCalendarViewStatusController' => 'applications/calendar/controller/PhabricatorCalendarViewStatusController.php',
614618
'PhabricatorChangesetResponse' => 'infrastructure/diff/PhabricatorChangesetResponse.php',
615619
'PhabricatorChatLogChannelListController' => 'applications/chatlog/controller/PhabricatorChatLogChannelListController.php',
616620
'PhabricatorChatLogChannelLogController' => 'applications/chatlog/controller/PhabricatorChatLogChannelLogController.php',
@@ -1125,6 +1129,8 @@
11251129
'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php',
11261130
'PhabricatorUserSSHKey' => 'applications/settings/storage/PhabricatorUserSSHKey.php',
11271131
'PhabricatorUserStatus' => 'applications/people/storage/PhabricatorUserStatus.php',
1132+
'PhabricatorUserStatusInvalidEpochException' => 'applications/people/exception/PhabricatorUserStatusInvalidEpochException.php',
1133+
'PhabricatorUserStatusOverlapException' => 'applications/people/exception/PhabricatorUserStatusOverlapException.php',
11281134
'PhabricatorUserTestCase' => 'applications/people/storage/__tests__/PhabricatorUserTestCase.php',
11291135
'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php',
11301136
'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerDAO.php',
@@ -1748,6 +1754,7 @@
17481754
'PhabricatorApplicationApplications' => 'PhabricatorApplication',
17491755
'PhabricatorApplicationAudit' => 'PhabricatorApplication',
17501756
'PhabricatorApplicationAuth' => 'PhabricatorApplication',
1757+
'PhabricatorApplicationCalendar' => 'PhabricatorApplication',
17511758
'PhabricatorApplicationConduit' => 'PhabricatorApplication',
17521759
'PhabricatorApplicationCountdown' => 'PhabricatorApplication',
17531760
'PhabricatorApplicationDaemons' => 'PhabricatorApplication',
@@ -1780,7 +1787,11 @@
17801787
'PhabricatorApplicationUIExamples' => 'PhabricatorApplication',
17811788
'PhabricatorApplicationsListController' => 'PhabricatorController',
17821789
'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController',
1783-
'PhabricatorAuditComment' => 'PhabricatorAuditDAO',
1790+
'PhabricatorAuditComment' =>
1791+
array(
1792+
0 => 'PhabricatorAuditDAO',
1793+
1 => 'PhabricatorMarkupInterface',
1794+
),
17841795
'PhabricatorAuditCommentEditor' => 'PhabricatorEditor',
17851796
'PhabricatorAuditCommitListView' => 'AphrontView',
17861797
'PhabricatorAuditController' => 'PhabricatorController',
@@ -1803,8 +1814,11 @@
18031814
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
18041815
'PhabricatorCalendarController' => 'PhabricatorController',
18051816
'PhabricatorCalendarDAO' => 'PhabricatorLiskDAO',
1817+
'PhabricatorCalendarDeleteStatusController' => 'PhabricatorCalendarController',
1818+
'PhabricatorCalendarEditStatusController' => 'PhabricatorCalendarController',
18061819
'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO',
18071820
'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase',
1821+
'PhabricatorCalendarViewStatusController' => 'PhabricatorCalendarController',
18081822
'PhabricatorChangesetResponse' => 'AphrontProxyResponse',
18091823
'PhabricatorChatLogChannelListController' => 'PhabricatorChatLogController',
18101824
'PhabricatorChatLogChannelLogController' => 'PhabricatorChatLogController',
@@ -2265,6 +2279,8 @@
22652279
'PhabricatorUserProfile' => 'PhabricatorUserDAO',
22662280
'PhabricatorUserSSHKey' => 'PhabricatorUserDAO',
22672281
'PhabricatorUserStatus' => 'PhabricatorUserDAO',
2282+
'PhabricatorUserStatusInvalidEpochException' => 'Exception',
2283+
'PhabricatorUserStatusOverlapException' => 'Exception',
22682284
'PhabricatorUserTestCase' => 'PhabricatorTestCase',
22692285
'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO',
22702286
'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO',

‎src/aphront/configuration/AphrontDefaultApplicationConfiguration.php

-4
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,6 @@ public function getURIMap() {
113113
'keyboardshortcut/' => 'PhabricatorHelpKeyboardShortcutController',
114114
),
115115

116-
'/calendar/' => array(
117-
'' => 'PhabricatorCalendarBrowseController',
118-
),
119-
120116
'/drydock/' => array(
121117
'' => 'DrydockResourceListController',
122118
'resource/' => 'DrydockResourceListController',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
/*
4+
* Copyright 2012 Facebook, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
final class PhabricatorApplicationCalendar extends PhabricatorApplication {
20+
21+
public function getShortDescription() {
22+
return pht('Dates and Stuff');
23+
}
24+
25+
public function getFlavorText() {
26+
return pht('Never miss an episode ever again.');
27+
}
28+
29+
public function getBaseURI() {
30+
return '/calendar/';
31+
}
32+
33+
public function getTitleGlyph() {
34+
// Unicode has a calendar character but it's in some distant code plane,
35+
// use "keyboard" since it looks vaguely similar.
36+
return "\xE2\x8C\xA8";
37+
}
38+
39+
public function getRoutes() {
40+
return array(
41+
'/calendar/' => array(
42+
'' => 'PhabricatorCalendarBrowseController',
43+
'status/' => array(
44+
'' => 'PhabricatorCalendarViewStatusController',
45+
'create/' =>
46+
'PhabricatorCalendarEditStatusController',
47+
'delete/(?P<id>[1-9]\d*)/' =>
48+
'PhabricatorCalendarDeleteStatusController',
49+
'edit/(?P<id>[1-9]\d*)/' =>
50+
'PhabricatorCalendarEditStatusController',
51+
'view/(?P<phid>[^/]+)/' =>
52+
'PhabricatorCalendarViewStatusController',
53+
),
54+
),
55+
);
56+
}
57+
58+
}

‎src/applications/calendar/controller/PhabricatorCalendarBrowseController.php

+46-9
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ final class PhabricatorCalendarBrowseController
2020
extends PhabricatorCalendarController {
2121

2222
public function processRequest() {
23+
$now = time();
2324
$request = $this->getRequest();
24-
$user = $request->getUser();
25-
26-
// TODO: These should be user-based and navigable in the interface.
27-
$year = idate('Y');
28-
$month = idate('m');
25+
$user = $request->getUser();
26+
$year_d = phabricator_format_local_time($now, $user, 'Y');
27+
$year = $request->getInt('year', $year_d);
28+
$month_d = phabricator_format_local_time($now, $user, 'm');
29+
$month = $request->getInt('month', $month_d);
2930

3031
$holidays = id(new PhabricatorCalendarHoliday())->loadAllWhere(
3132
'day BETWEEN %s AND %s',
@@ -39,6 +40,7 @@ public function processRequest() {
3940
strtotime("{$year}-{$month}-01 next month"));
4041

4142
$month_view = new AphrontCalendarMonthView($month, $year);
43+
$month_view->setBrowseURI($request->getRequestURI());
4244
$month_view->setUser($user);
4345
$month_view->setHolidays($holidays);
4446

@@ -53,18 +55,53 @@ public function processRequest() {
5355
$status_text = $status->getTextStatus();
5456
$event->setUserPHID($status->getUserPHID());
5557
$event->setName("{$name_text} ({$status_text})");
56-
$event->setDescription($status->getStatusDescription($user));
58+
$details = '';
59+
if ($status->getDescription()) {
60+
$details = "\n\n".rtrim(phutil_escape_html($status->getDescription()));
61+
}
62+
$event->setDescription(
63+
$status->getTerseSummary($user).$details
64+
);
5765
$month_view->addEvent($event);
5866
}
5967

60-
return $this->buildStandardPageResponse(
68+
$nav = $this->buildSideNavView();
69+
$nav->selectFilter('edit');
70+
$nav->appendChild(
6171
array(
72+
$this->getNoticeView(),
6273
'<div style="padding: 2em;">',
6374
$month_view,
6475
'</div>',
65-
),
66-
array(
76+
));
77+
78+
return $this->buildApplicationPage(
79+
$nav,
80+
array(
6781
'title' => 'Calendar',
82+
'device' => true,
6883
));
6984
}
85+
86+
private function getNoticeView() {
87+
$request = $this->getRequest();
88+
$view = null;
89+
90+
if ($request->getExists('created')) {
91+
$view = id(new AphrontErrorView())
92+
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
93+
->setTitle(pht('Successfully created your status.'));
94+
} else if ($request->getExists('updated')) {
95+
$view = id(new AphrontErrorView())
96+
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
97+
->setTitle(pht('Successfully updated your status.'));
98+
} else if ($request->getExists('deleted')) {
99+
$view = id(new AphrontErrorView())
100+
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
101+
->setTitle(pht('Successfully deleted your status.'));
102+
}
103+
104+
return $view;
105+
}
106+
70107
}

‎src/applications/calendar/controller/PhabricatorCalendarController.php

+16-11
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,26 @@
1818

1919
abstract class PhabricatorCalendarController extends PhabricatorController {
2020

21-
public function buildStandardPageResponse($view, array $data) {
2221

23-
$page = $this->buildStandardPageView();
22+
protected function buildSideNavView(PhabricatorUserStatus $status = null) {
23+
$nav = new AphrontSideNavFilterView();
24+
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
2425

25-
$page->setApplicationName('Calendar');
26-
$page->setBaseURI('/calendar/');
27-
$page->setTitle(idx($data, 'title'));
26+
$nav->addFilter('', pht('Calendar'), $this->getApplicationURI());
2827

29-
// Unicode has a calendar character but it's in some distant code plane,
30-
// use "keyboard" since it looks vaguely similar.
31-
$page->setGlyph("\xE2\x8C\xA8");
32-
$page->appendChild($view);
28+
$nav->addSpacer();
3329

34-
$response = new AphrontWebpageResponse();
35-
return $response->setContent($page->render());
30+
$nav->addLabel(pht('Create Events'));
31+
$nav->addFilter('status/create/', pht('New Status'));
32+
33+
$nav->addSpacer();
34+
$nav->addLabel(pht('Your Events'));
35+
if ($status && $status->getID()) {
36+
$nav->addFilter('status/edit/'.$status->getID().'/', pht('Edit Status'));
37+
}
38+
$nav->addFilter('status/', pht('Upcoming Statuses'));
39+
40+
return $nav;
3641
}
3742

3843
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
/*
4+
* Copyright 2012 Facebook, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
final class PhabricatorCalendarDeleteStatusController
20+
extends PhabricatorCalendarController {
21+
22+
private $id;
23+
24+
public function willProcessRequest(array $data) {
25+
$this->id = idx($data, 'id');
26+
}
27+
28+
public function processRequest() {
29+
$request = $this->getRequest();
30+
$user = $request->getUser();
31+
$status = id(new PhabricatorUserStatus())
32+
->loadOneWhere('id = %d', $this->id);
33+
34+
if (!$status) {
35+
return new Aphront404Response();
36+
}
37+
if ($status->getUserPHID() != $user->getPHID()) {
38+
return new Aphront403Response();
39+
}
40+
41+
if ($request->isFormPost()) {
42+
$status->delete();
43+
$uri = new PhutilURI($this->getApplicationURI());
44+
$uri->setQueryParams(
45+
array(
46+
'deleted' => true,
47+
)
48+
);
49+
return id(new AphrontRedirectResponse())
50+
->setURI($uri);
51+
}
52+
53+
$dialog = new AphrontDialogView();
54+
$dialog->setUser($user);
55+
$dialog->setTitle(pht('Really delete status?'));
56+
$dialog->appendChild(phutil_render_tag(
57+
'p',
58+
array(),
59+
pht('Permanently delete this status? This action can not be undone.')
60+
));
61+
$dialog->addSubmitButton(pht('Delete'));
62+
$dialog->addCancelButton(
63+
$this->getApplicationURI('status/edit/'.$status->getID().'/')
64+
);
65+
66+
return id(new AphrontDialogResponse())->setDialog($dialog);
67+
68+
}
69+
70+
}

0 commit comments

Comments
 (0)
Failed to load comments.