diff --git a/resources/sql/patches/044.countdown.sql b/resources/sql/patches/044.countdown.sql new file mode 100644 index 0000000000..d57c089da8 --- /dev/null +++ b/resources/sql/patches/044.countdown.sql @@ -0,0 +1,16 @@ +CREATE DATABASE phabricator_countdown; + +CREATE TABLE phabricator_countdown.countdown_timer ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + authorPHID VARCHAR(64) BINARY NOT NULL, + datepoint INT UNSIGNED NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL +); + +INSERT INTO phabricator_directory.directory_item + (name, description, href, categoryID, sequence, dateCreated, dateModified) +VALUES + ("Counterdown", "T-minus X to Y", "/countdown/", 5, 350, + UNIX_TIMESTAMP(), UNIX_TIMESTAMP()); diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 4607a3d87e..459eccacae 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -161,6 +161,16 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/css/application/differential/core.css', ), + 0 => + array( + 'uri' => '/res/39de799e/rsrc/js/javelin/docs/Base.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-install', + ), + 'disk' => '/rsrc/js/javelin/docs/Base.js', + ), 'differential-inline-comment-editor' => array( 'uri' => '/res/5e4f0aa4/rsrc/js/application/differential/DifferentialInlineCommentEditor.js', @@ -293,16 +303,6 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/javelin/lib/behavior.js', ), - 0 => - array( - 'uri' => '/res/39de799e/rsrc/js/javelin/docs/Base.js', - 'type' => 'js', - 'requires' => - array( - 0 => 'javelin-install', - ), - 'disk' => '/rsrc/js/javelin/docs/Base.js', - ), 'javelin-behavior-aphront-basic-tokenizer' => array( 'uri' => '/res/bce3961b/rsrc/js/application/core/behavior-tokenizer.js', @@ -342,6 +342,18 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/behavior-form.js', ), + 'javelin-behavior-countdown-timer' => + array( + 'uri' => '/res/48477cc8/rsrc/js/application/countdown/timer.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-util', + ), + 'disk' => '/rsrc/js/application/countdown/timer.js', + ), 'javelin-behavior-dark-console' => array( 'uri' => '/res/c80156c4/rsrc/js/application/core/behavior-dark-console.js', @@ -941,6 +953,15 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/css/core/core.css', ), + 'phabricator-countdown-css' => + array( + 'uri' => '/res/7fd1e21f/rsrc/css/application/countdown/timer.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/countdown/timer.css', + ), 'phabricator-directory-css' => array( 'uri' => '/res/a3d307c5/rsrc/css/application/directory/phabricator-directory.css', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 344b963863..87d3bb7295 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -284,6 +284,12 @@ phutil_register_library_map(array( 'PhabricatorConduitLogController' => 'applications/conduit/controller/log', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog', 'PhabricatorController' => 'applications/base/controller/base', + 'PhabricatorCountdownController' => 'applications/countdown/controller/base', + 'PhabricatorCountdownDAO' => 'applications/countdown/storage/base', + 'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/delete', + 'PhabricatorCountdownEditController' => 'applications/countdown/controller/edit', + 'PhabricatorCountdownListController' => 'applications/countdown/controller/list', + 'PhabricatorCountdownViewController' => 'applications/countdown/controller/view', 'PhabricatorDaemon' => 'infrastructure/daemon/base', 'PhabricatorDaemonCombinedLogController' => 'applications/daemon/controller/combined', 'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/console', @@ -487,6 +493,7 @@ phutil_register_library_map(array( 'PhabricatorTimelineEvent' => 'infrastructure/daemon/timeline/storage/event', 'PhabricatorTimelineEventData' => 'infrastructure/daemon/timeline/storage/eventdata', 'PhabricatorTimelineIterator' => 'infrastructure/daemon/timeline/cursor/iterator', + 'PhabricatorTimer' => 'applications/countdown/storage/timer', 'PhabricatorTransformedFile' => 'applications/files/storage/transformed', 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base', @@ -747,6 +754,12 @@ phutil_register_library_map(array( 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', 'PhabricatorController' => 'AphrontController', + 'PhabricatorCountdownController' => 'PhabricatorController', + 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', + 'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController', + 'PhabricatorCountdownEditController' => 'PhabricatorCountdownController', + 'PhabricatorCountdownListController' => 'PhabricatorCountdownController', + 'PhabricatorCountdownViewController' => 'PhabricatorCountdownController', 'PhabricatorDaemon' => 'PhutilDaemon', 'PhabricatorDaemonCombinedLogController' => 'PhabricatorDaemonController', 'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController', @@ -925,6 +938,7 @@ phutil_register_library_map(array( 'PhabricatorTimelineDAO' => 'PhabricatorLiskDAO', 'PhabricatorTimelineEvent' => 'PhabricatorTimelineDAO', 'PhabricatorTimelineEventData' => 'PhabricatorTimelineDAO', + 'PhabricatorTimer' => 'PhabricatorCountdownDAO', 'PhabricatorTransformedFile' => 'PhabricatorFileDAO', 'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index a7a28111a9..629f455f9f 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -315,6 +315,17 @@ class AphrontDefaultApplicationConfiguration '/help/' => array( 'keyboardshortcut/$' => 'PhabricatorHelpKeyboardShortcutController', ), + + '/countdown/' => array( + '$' + => 'PhabricatorCountdownListController', + '(?P\d+)/$' + => 'PhabricatorCountdownViewController', + 'edit/(?:(?P\d+)/)?$' + => 'PhabricatorCountdownEditController', + 'delete/(?P\d+)/$' + => 'PhabricatorCountdownDeleteController' + ), ); } diff --git a/src/applications/countdown/controller/base/PhabricatorCountdownController.php b/src/applications/countdown/controller/base/PhabricatorCountdownController.php new file mode 100644 index 0000000000..801dd2a60b --- /dev/null +++ b/src/applications/countdown/controller/base/PhabricatorCountdownController.php @@ -0,0 +1,44 @@ +buildStandardPageView(); + + $page->setApplicationName('Countdown'); + $page->setBaseURI('/countdown/'); + $page->setTitle(idx($data, 'title')); + $page->setGlyph("\xE2\x9A\xB2"); + $page->setTabs( + array( + 'create' => array( + 'href' => '/countdown/', + 'name' => 'List', + ), + ), + idx($data, 'tab')); + + $page->appendChild($view); + + $response = new AphrontWebpageResponse(); + return $response->setContent($page->render()); + + } +} diff --git a/src/applications/countdown/controller/base/__init__.php b/src/applications/countdown/controller/base/__init__.php new file mode 100644 index 0000000000..06b7b3c80e --- /dev/null +++ b/src/applications/countdown/controller/base/__init__.php @@ -0,0 +1,15 @@ +id = $data['id']; + } + + public function processRequest() { + + $request = $this->getRequest(); + $user = $request->getUser(); + + $timer = id(new PhabricatorTimer())->load($this->id); + if (!$timer) { + return new Aphront404Response(); + } + + if (($timer->getAuthorPHID() !== $user->getPHID()) + && $user->getIsAdmin() === false) { + return new Aphront404Response(); + } + + if ($request->isFormPost()) { + $timer->delete(); + return id(new AphrontRedirectResponse()) + ->setURI('/countdown/'); + } + + $dialog = new AphrontDialogView(); + $dialog->setUser($request->getUser()); + $dialog->setTitle('Really delete this countdown?'); + $dialog->appendChild("Are you sure you want to delete this countdown?"); + $dialog->addSubmitButton('Delete'); + $dialog->addCancelButton('/countdown/'); + $dialog->setSubmitURI($request->getPath()); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + +} diff --git a/src/applications/countdown/controller/delete/__init__.php b/src/applications/countdown/controller/delete/__init__.php new file mode 100644 index 0000000000..2f550ae3dd --- /dev/null +++ b/src/applications/countdown/controller/delete/__init__.php @@ -0,0 +1,19 @@ +id = idx($data, 'id'); + } + + public function processRequest() { + + $request = $this->getRequest(); + $user = $request->getUser(); + $action_label = 'Create Timer'; + + if ($this->id) { + $timer = id(new PhabricatorTimer())->load($this->id); + // If no timer is found + if (!$timer) { + return new Aphront404Response(); + } + + if (($timer->getAuthorPHID() != $user->getPHID()) + && $user->getIsAdmin() == false) { + return new Aphront404Response(); + } + + $action_label = 'Update Timer'; + } else { + $timer = new PhabricatorTimer(); + } + + $error_view = null; + $e_text = null; + + if ($request->isFormPost()) { + $errors = array(); + $title = $request->getStr('title'); + $datepoint = $request->getStr('datepoint'); + $timestamp = strtotime($datepoint); + + $e_text = null; + if (!strlen($title)) { + $e_text = 'Required'; + $errors[] = 'You must give it a name'; + } + + if ($timestamp === false) { + $errors[] = 'You entered an incorrect date. You can enter date like'. + ' \'2011-06-26 13:33:37\' to create an event at'. + ' 13:33:37 on the 26th of June 2011'; + } + + $timer->setTitle($title); + $timer->setDatePoint($timestamp); + + if (!count($errors)) { + $timer->setAuthorPHID($user->getPHID()); + $timer->save(); + return id(new AphrontRedirectResponse()) + ->setURI('/countdown/'.$timer->getID()); + } + else { + $error_view = id(new AphrontErrorView()) + ->setErrors($errors) + ->setTitle('It\'s not The Final Countdown (du nu nuuu nun)' . + ' until you fix these problem'); + } + } + + $form = id(new AphrontFormView()) + ->setUser($user) + ->setAction($request->getRequestURI()->getPath()) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Title') + ->setValue($timer->getTitle()) + ->setName('title')) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('End date') + ->setValue(strftime("%F %H:%M:%S", $timer->getDatePoint())) + ->setName('datepoint') + ->setCaption('Post any date that is parsable by strtotime')) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton('/countdown/') + ->setValue($action_label)); + + $panel = id(new AphrontPanelView()) + ->setWidth(AphrontPanelView::WIDTH_FORM) + ->setHeader($action_label) + ->appendChild($form); + + return $this->buildStandardPageResponse(array( + $error_view, + $panel + ), + array( + 'title' => 'Countdown management', + 'tab' => 'management', + )); + } +} diff --git a/src/applications/countdown/controller/edit/__init__.php b/src/applications/countdown/controller/edit/__init__.php new file mode 100644 index 0000000000..d7534b78c0 --- /dev/null +++ b/src/applications/countdown/controller/edit/__init__.php @@ -0,0 +1,22 @@ +getRequest(); + $user = $request->getUser(); + + $pager = new AphrontPagerView(); + $pager->setOffset($request->getInt('page')); + $pager->setURI($request->getRequestURI(), 'page'); + + $timers = id(new PhabricatorTimer())->loadAllWhere( + '1 = 1 ORDER BY id DESC LIMIT %d, %d', + $pager->getOffset(), + $pager->getPageSize() + 1); + + $timers = $pager->sliceResults($timers); + + $rows = array(); + foreach ($timers as $timer) { + + $control_buttons = array(); + $control_buttons[] = phutil_render_tag( + 'a', + array( + 'class' => 'small button grey', + 'href' => '/countdown/'.$timer->getID().'/', + ), + 'View'); + + if ($user->getIsAdmin() || + ($user->getPHID() == $timer->getAuthorPHID())) { + + $control_buttons[] = phutil_render_tag( + 'a', + array( + 'class' => 'small button grey', + 'href' => '/countdown/edit/'.$timer->getID().'/' + ), + 'Edit'); + + $control_buttons[] = javelin_render_tag( + 'a', + array( + 'class' => 'small button grey', + 'href' => '/countdown/delete/'.$timer->getID().'/', + 'sigil' => 'workflow' + ), + 'Delete'); + + } + + $rows[] = array( + phutil_escape_html($timer->getID()), + phutil_escape_html($timer->getTitle()), + phabricator_format_timestamp($timer->getDatepoint()), + implode('', $control_buttons) + ); + } + + $table = new AphrontTableView($rows); + $table->setHeaders( + array( + 'ID', + 'Title', + 'End Date', + 'Action' + )); + + $table->setColumnClasses( + array( + null, + null, + null, + 'action' + )); + + $panel = id(new AphrontPanelView()) + ->appendChild($table) + ->setHeader('Timers') + ->setCreateButton('Create Timer', '/countdown/edit/') + ->appendChild($pager); + + return $this->buildStandardPageResponse($panel, + array( + 'title' => 'Countdown', + 'tab' => 'countdown', + )); + } +} diff --git a/src/applications/countdown/controller/list/__init__.php b/src/applications/countdown/controller/list/__init__.php new file mode 100644 index 0000000000..14fadffd7f --- /dev/null +++ b/src/applications/countdown/controller/list/__init__.php @@ -0,0 +1,21 @@ +id = $data['id']; + } + + + public function processRequest() { + + $request = $this->getRequest(); + $user = $request->getUser(); + $timer = id(new PhabricatorTimer())->load($this->id); + if (!$timer) { + return new Aphront404Response(); + } + + require_celerity_resource('phabricator-countdown-css'); + + $content = + '
+

'. + phutil_escape_html($timer->getTitle()).' +

+
+ + + + + + + + + + + + +
DaysHoursMinutesSeconds
+
+
'; + + Javelin::initBehavior('countdown-timer', array( + 'timestamp' => $timer->getDatepoint() + )); + + $panel = $content; + + return $this->buildStandardPageResponse($panel, + array( + 'title' => 'T-minus..', + 'tab' => 'view', + )); + } + +} diff --git a/src/applications/countdown/controller/view/__init__.php b/src/applications/countdown/controller/view/__init__.php new file mode 100644 index 0000000000..7689aa507d --- /dev/null +++ b/src/applications/countdown/controller/view/__init__.php @@ -0,0 +1,19 @@ +