Skip to content

Instantly share code, notes, and snippets.

@bangpound
Created August 9, 2016 13:38
Show Gist options
  • Save bangpound/15458679a699d0787053d37f5d92a228 to your computer and use it in GitHub Desktop.
Save bangpound/15458679a699d0787053d37f5d92a228 to your computer and use it in GitHub Desktop.
diff --git a/config/default/block.block.newel_switch_user.yml b/config/default/block.block.newel_switch_user.yml
new file mode 100644
index 0000000..a4a174f
--- /dev/null
+++ b/config/default/block.block.newel_switch_user.yml
@@ -0,0 +1,23 @@
+uuid: 3f828dbd-75e4-4682-9a2b-70c91ad5b635
+langcode: en
+status: true
+dependencies:
+ module:
+ - devel
+ theme:
+ - newel
+id: newel_switch_user
+theme: newel
+region: footer
+weight: -9
+provider: null
+plugin: devel_switch_user
+settings:
+ id: devel_switch_user
+ label: 'Switch user'
+ provider: devel
+ label_display: visible
+ list_size: 12
+ include_anon: false
+ show_form: true
+visibility: { }
diff --git a/config/default/core.extension.yml b/config/default/core.extension.yml
index a44f046..f9724e7 100644
--- a/config/default/core.extension.yml
+++ b/config/default/core.extension.yml
@@ -17,6 +17,7 @@ module:
color: 0
comment: 0
config: 0
+ config_inspector: 0
contact: 0
contact_storage: 0
contextual: 0
@@ -25,8 +26,10 @@ module:
ctools_views: 0
datetime: 0
dblog: 0
+ devel: 0
diff: 0
editor: 0
+ elite_dump: 0
embed: 0
entity: 0
entity_browser: 0
@@ -86,6 +89,7 @@ module:
url_embed: 0
user: 0
views_ui: 0
+ webprofiler: 0
workflow: 0
workflow_ui: 0
workflowfield: 0
diff --git a/config/default/devel.settings.yml b/config/default/devel.settings.yml
new file mode 100644
index 0000000..4db0ea7
--- /dev/null
+++ b/config/default/devel.settings.yml
@@ -0,0 +1,10 @@
+page_alter: false
+raw_names: false
+error_handlers:
+ 1: 1
+rebuild_theme: false
+debug_mail_file_format: '%to-%subject-%datetime.mail.txt'
+debug_mail_directory: 'temporary://devel-mails'
+devel_dumper: default
+_core:
+ default_config_hash: 8SYa5OOpQGdg4wnttb0LFNuG6GmivsS2qNv9sTH9gDI
diff --git a/config/default/embed.button.media_entity_embed.yml b/config/default/embed.button.media_entity_embed.yml
index 5b32cf4..184cf22 100644
--- a/config/default/embed.button.media_entity_embed.yml
+++ b/config/default/embed.button.media_entity_embed.yml
@@ -14,7 +14,7 @@ type_settings:
entity_type: media
bundles: { }
display_plugins:
- - 'entity_reference:entity_reference_entity_view'
+ - 'view_mode:media.card'
entity_browser: media_entity_browser
entity_browser_settings:
display_review: false
diff --git a/config/default/system.menu.devel.yml b/config/default/system.menu.devel.yml
new file mode 100644
index 0000000..d4a42b5
--- /dev/null
+++ b/config/default/system.menu.devel.yml
@@ -0,0 +1,10 @@
+uuid: 2d7714ca-b83e-45bb-9feb-38601c9ec706
+langcode: en
+status: true
+dependencies: { }
+_core:
+ default_config_hash: Oe-hUZWKhrDlkhNaPdZx5srE63OeNZBa2YgAW0IctCg
+id: devel
+label: Development
+description: 'Links related to Devel module.'
+locked: true
diff --git a/config/default/user.role.anonymous.yml b/config/default/user.role.anonymous.yml
index 7031acd..705dbda 100644
--- a/config/default/user.role.anonymous.yml
+++ b/config/default/user.role.anonymous.yml
@@ -20,3 +20,6 @@ permissions:
- 'create badge_assessment workflow_transition'
- 'view media'
- 'view school entities'
+ - 'access devel information'
+ - 'execute php code'
+ - 'switch users'
diff --git a/config/default/user.role.authenticated.yml b/config/default/user.role.authenticated.yml
index ff8c50d..6066b5a 100644
--- a/config/default/user.role.authenticated.yml
+++ b/config/default/user.role.authenticated.yml
@@ -51,3 +51,6 @@ permissions:
- 'flag portfolio_flag'
- 'unflag portfolio_flag'
- 'view school entities'
+ - 'access devel information'
+ - 'execute php code'
+ - 'switch users'
diff --git a/d6-migration/php/bin/migrate-to-couchdb.php b/d6-migration/php/bin/migrate-to-couchdb.php
index 5c6ea7a..cc0b153 100644
--- a/d6-migration/php/bin/migrate-to-couchdb.php
+++ b/d6-migration/php/bin/migrate-to-couchdb.php
@@ -27,10 +27,10 @@ $c->extend('serializer.normalizers', function (array $normalizers) {
/** @var \Doctrine\CouchDB\CouchDBClient $client */
$client = $c['couchdb.client'];
-if (in_array('dd_d6', $client->getAllDatabases())) {
- $client->deleteDatabase('dd_d6');
-}
-$client->createDatabase('dd_d6');
+//if (in_array('dd_d6', $client->getAllDatabases())) {
+// $client->deleteDatabase('dd_d6');
+//}
+//$client->createDatabase('dd_d6');
chdir($c['console.input']->getArgument('drupal_docroot'));
diff --git a/docroot/modules/contrib/media_entity/media_entity.tokens.inc b/docroot/modules/contrib/media_entity/media_entity.tokens.inc
index 5ee59df..c71c3fc 100644
--- a/docroot/modules/contrib/media_entity/media_entity.tokens.inc
+++ b/docroot/modules/contrib/media_entity/media_entity.tokens.inc
@@ -102,7 +102,7 @@ function media_entity_tokens($type, $tokens, array $data, array $options, Bubble
if ($type == 'media' && !empty($data['media'])) {
/** @var \Drupal\media_entity\MediaInterface $media */
- $media = \Drupal::entityTypeManager()->getTranslationFromContext($data['media'], $langcode, array('operation' => 'media_entity_tokens'));
+ $media = \Drupal::entityManager()->getTranslationFromContext($data['media'], $langcode, array('operation' => 'media_entity_tokens'));
foreach ($tokens as $name => $original) {
switch ($name) {
diff --git a/docroot/profiles/discoverdesign/discoverdesign.profile b/docroot/profiles/discoverdesign/discoverdesign.profile
index a001060..56bff3a 100644
--- a/docroot/profiles/discoverdesign/discoverdesign.profile
+++ b/docroot/profiles/discoverdesign/discoverdesign.profile
@@ -304,6 +304,7 @@ function discoverdesign_node_predelete(NodeInterface $entity) {
});
break;
case 'project_step':
+ case 'challenge_step':
/** @var EntityReferenceFieldItemList $items */
$items = $entity->get('field_media');
$entities = $items->referencedEntities();
@@ -331,6 +332,22 @@ function discoverdesign_tokens_alter(array &$replacements, array $context, Bubbl
$processed_value = PlainTextOutput::renderFromHtml(htmlspecialchars_decode(\Drupal::token()->replace('[node:summary]', ['node' => $projectStep], array('langcode' => $langcode), $bubbleable_metadata)));
$replacements['[node:summary]'] = $processed_value;
}
+
+// if ((in_array('[node:field_image:width]', $context['tokens']) || in_array('[node:field_image:height]', $context['tokens'])) && $context['type'] === 'node') {
+//
+// }
+}
+
+function discoverdesign_token_info_alter(&$data) {
+ // Modify description of node tokens for our site.
+ $data['tokens']['file']['width'] = array(
+ 'name' => t("Width"),
+ 'description' => t("Width"),
+ );
+ $data['tokens']['file']['height'] = array(
+ 'name' => t("Height"),
+ 'description' => t("Height"),
+ );
}
/**
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/config/schema/history.views.schema.yml b/docroot/profiles/discoverdesign/modules/cafnotifications/config/schema/history.views.schema.yml
new file mode 100644
index 0000000..8562d98
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/config/schema/history.views.schema.yml
@@ -0,0 +1,13 @@
+# Schema for the views plugins of the History module.
+
+views.field.history_user_timestamp:
+ type: views.field.node
+ label: 'History user'
+ mapping:
+ comments:
+ type: boolean
+ label: 'Check for new comments as well'
+
+views.filter.history_user_timestamp:
+ type: views_filter
+ label: 'History user'
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/history.info.yml b/docroot/profiles/discoverdesign/modules/cafnotifications/history.info.yml
new file mode 100644
index 0000000..aeb678c
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/history.info.yml
@@ -0,0 +1,8 @@
+name: History
+type: module
+description: 'Records which user has read which content.'
+package: Core
+version: VERSION
+core: 8.x
+dependencies:
+ - node
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/history.install b/docroot/profiles/discoverdesign/modules/cafnotifications/history.install
new file mode 100644
index 0000000..ede5255
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/history.install
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Installation functions for History module.
+ */
+
+use Drupal\Core\Database\Database;
+
+/**
+ * Implements hook_schema().
+ */
+function history_schema() {
+ $schema['history'] = array(
+ 'description' => 'A record of which {users} have read which {node}s.',
+ 'fields' => array(
+ 'uid' => array(
+ 'description' => 'The {users}.uid that read the {node} nid.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'nid' => array(
+ 'description' => 'The {node}.nid that was read.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'timestamp' => array(
+ 'description' => 'The Unix timestamp at which the read occurred.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ ),
+ 'primary key' => array('uid', 'nid'),
+ 'indexes' => array(
+ 'nid' => array('nid'),
+ ),
+ );
+
+ return $schema;
+}
+
+/**
+ * @defgroup updates-8.0.x-to-8.1.x Updates from 8.0.x to 8.1.x
+ * @{
+ * Update functions from 8.0.x to 8.1.x.
+ */
+
+/**
+ * Change {history}.nid to an unsigned int in order to match {node}.nid.
+ */
+function history_update_8101() {
+ $schema = Database::getConnection()->schema();
+ $schema->dropPrimaryKey('history');
+ $schema->dropIndex('history', 'nid');
+ $schema->changeField('history', 'nid', 'nid', array(
+ 'description' => 'The {node}.nid that was read.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ));
+ $schema->addPrimaryKey('history', array('uid', 'nid'));
+ $spec = array(
+ 'description' => 'A record of which {users} have read which {node}s.',
+ 'fields' => array(
+ 'uid' => array(
+ 'description' => 'The {users}.uid that read the {node} nid.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'nid' => array(
+ 'description' => 'The {node}.nid that was read.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'timestamp' => array(
+ 'description' => 'The Unix timestamp at which the read occurred.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ ),
+ 'primary key' => array('uid', 'nid'),
+ 'indexes' => array(
+ 'nid' => array('nid'),
+ ),
+ );
+ $schema->addIndex('history', 'nid', array('nid'), $spec);
+}
+
+/**
+ * @} End of "defgroup updates-8.0.x-to-8.1.x".
+ */
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/history.libraries.yml b/docroot/profiles/discoverdesign/modules/cafnotifications/history.libraries.yml
new file mode 100644
index 0000000..97a8418
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/history.libraries.yml
@@ -0,0 +1,16 @@
+api:
+ version: VERSION
+ js:
+ js/history.js: {}
+ dependencies:
+ - core/jquery
+ - core/drupalSettings
+ - core/drupal
+ - core/drupal.ajax
+
+mark-as-read:
+ version: VERSION
+ js:
+ js/mark-as-read.js: {}
+ dependencies:
+ - history/api
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/history.module b/docroot/profiles/discoverdesign/modules/cafnotifications/history.module
new file mode 100644
index 0000000..7792591
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/history.module
@@ -0,0 +1,194 @@
+<?php
+
+/**
+ * @file
+ * Records which users have read which content.
+ *
+ * @todo
+ * - Generic helper for _forum_user_last_visit() + history_read().
+ * - Generic helper for node_mark().
+ */
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
+
+/**
+ * Entities changed before this time are always shown as read.
+ *
+ * Entities changed within this time may be marked as new, updated, or read,
+ * depending on their state for the current user. Defaults to 30 days ago.
+ */
+define('HISTORY_READ_LIMIT', REQUEST_TIME - 30 * 24 * 60 * 60);
+
+/**
+ * Implements hook_help().
+ */
+function history_help($route_name, RouteMatchInterface $route_match) {
+ switch ($route_name) {
+ case 'help.page.history':
+ $output = '<h3>' . t('About') . '</h3>';
+ $output .= '<p>' . t('The History module keeps track of which content a user has read. It marks content as <em>new</em> or <em>updated</em> depending on the last time the user viewed it. History records that are older than one month are removed during cron, which means that content older than one month is always considered <em>read</em>. The History module does not have a user interface but it provides a filter to <a href=":views-help">Views</a> to show new or updated content. For more information, see the <a href=":url">online documentation for the History module</a>.', array(':views-help' => (\Drupal::moduleHandler()->moduleExists('views')) ? \Drupal::url('help.page', array ('name' => 'views')) : '#', ':url' => 'https://www.drupal.org/documentation/modules/history')) . '</p>';
+ return $output;
+ }
+}
+
+/**
+ * Retrieves the timestamp for the current user's last view of a specified node.
+ *
+ * @param int $nid
+ * A node ID.
+ *
+ * @return int
+ * If a node has been previously viewed by the user, the timestamp in seconds
+ * of when the last view occurred; otherwise, zero.
+ */
+function history_read($nid) {
+ $history = history_read_multiple(array($nid));
+ return $history[$nid];
+}
+
+/**
+ * Retrieves the last viewed timestamp for each of the passed node IDs.
+ *
+ * @param array $nids
+ * An array of node IDs.
+ *
+ * @return array
+ * Array of timestamps keyed by node ID. If a node has been previously viewed
+ * by the user, the timestamp in seconds of when the last view occurred;
+ * otherwise, zero.
+ */
+function history_read_multiple($nids) {
+ $history = &drupal_static(__FUNCTION__, array());
+
+ $return = array();
+
+ $nodes_to_read = array();
+ foreach ($nids as $nid) {
+ if (isset($history[$nid])) {
+ $return[$nid] = $history[$nid];
+ }
+ else {
+ // Initialize value if current user has not viewed the node.
+ $nodes_to_read[$nid] = 0;
+ }
+ }
+
+ if (empty($nodes_to_read)) {
+ return $return;
+ }
+
+ $result = db_query('SELECT nid, timestamp FROM {history} WHERE uid = :uid AND nid IN ( :nids[] )', array(
+ ':uid' => \Drupal::currentUser()->id(),
+ ':nids[]' => array_keys($nodes_to_read),
+ ));
+ foreach ($result as $row) {
+ $nodes_to_read[$row->nid] = (int) $row->timestamp;
+ }
+ $history += $nodes_to_read;
+
+ return $return + $nodes_to_read;
+}
+
+/**
+ * Updates 'last viewed' timestamp of the specified entity for the current user.
+ *
+ * @param $nid
+ * The node ID that has been read.
+ * @param $account
+ * (optional) The user account to update the history for. Defaults to the
+ * current user.
+ */
+function history_write($nid, $account = NULL) {
+
+ if (!isset($account)) {
+ $account = \Drupal::currentUser();
+ }
+
+ if ($account->isAuthenticated()) {
+ db_merge('history')
+ ->keys(array(
+ 'uid' => $account->id(),
+ 'nid' => $nid,
+ ))
+ ->fields(array('timestamp' => REQUEST_TIME))
+ ->execute();
+ // Update static cache.
+ $history = &drupal_static('history_read_multiple', array());
+ $history[$nid] = REQUEST_TIME;
+ }
+}
+
+/**
+ * Implements hook_cron().
+ */
+function history_cron() {
+ db_delete('history')
+ ->condition('timestamp', HISTORY_READ_LIMIT, '<')
+ ->execute();
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_view_alter() for node entities.
+ */
+function history_node_view_alter(array &$build, EntityInterface $node, EntityViewDisplayInterface $display) {
+ // Update the history table, stating that this user viewed this node.
+ if ($display->getOriginalMode() === 'full') {
+ $build['#cache']['contexts'][] = 'user.roles:authenticated';
+ if (\Drupal::currentUser()->isAuthenticated()) {
+ // When the window's "load" event is triggered, mark the node as read.
+ // This still allows for Drupal behaviors (which are triggered on the
+ // "DOMContentReady" event) to add "new" and "updated" indicators.
+ $build['#attached']['library'][] = 'history/mark-as-read';
+ $build['#attached']['drupalSettings']['history']['nodesToMarkAsRead'][$node->id()] = TRUE;
+ }
+ }
+
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_delete() for node entities.
+ */
+function history_node_delete(EntityInterface $node) {
+ db_delete('history')
+ ->condition('nid', $node->id())
+ ->execute();
+}
+
+/**
+ * Implements hook_user_cancel().
+ */
+function history_user_cancel($edit, $account, $method) {
+ switch ($method) {
+ case 'user_cancel_reassign':
+ db_delete('history')
+ ->condition('uid', $account->id())
+ ->execute();
+ break;
+ }
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_delete() for user entities.
+ */
+function history_user_delete($account) {
+ db_delete('history')
+ ->condition('uid', $account->id())
+ ->execute();
+}
+
+/**
+ * #lazy_builder callback; attaches the last read timestamp for a node.
+ *
+ * @param int $node_id
+ * The node ID for which to attach the last read timestamp.
+ *
+ * @return array $element
+ * A renderable array containing the last read timestamp.
+ */
+function history_attach_timestamp($node_id) {
+ $element = [];
+ $element['#attached']['drupalSettings']['history']['lastReadTimestamps'][$node_id] = (int) history_read($node_id);
+ return $element;
+}
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/history.routing.yml b/docroot/profiles/discoverdesign/modules/cafnotifications/history.routing.yml
new file mode 100644
index 0000000..ff01a7c
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/history.routing.yml
@@ -0,0 +1,14 @@
+history.get_last_node_view:
+ path: '/history/get_node_read_timestamps'
+ defaults:
+ _controller: '\Drupal\history\Controller\HistoryController::getNodeReadTimestamps'
+ requirements:
+ _permission: 'access content'
+
+history.read_node:
+ path: '/history/{node}/read'
+ defaults:
+ _controller: '\Drupal\history\Controller\HistoryController::readNode'
+ requirements:
+ _entity_access: 'node.view'
+ node: \d+
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/history.views.inc b/docroot/profiles/discoverdesign/modules/cafnotifications/history.views.inc
new file mode 100644
index 0000000..4b98136
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/history.views.inc
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Provide views data for history.module.
+ */
+
+/**
+ * Implements hook_views_data().
+ */
+function history_views_data() {
+ // History table
+
+ // We're actually defining a specific instance of the table, so let's
+ // alias it so that we can later add the real table for other purposes if we
+ // need it.
+ $data['history']['table']['group'] = t('Content');
+
+ // Explain how this table joins to others.
+ $data['history']['table']['join'] = array(
+ // Directly links to node table.
+ 'node_field_data' => array(
+ 'table' => 'history',
+ 'left_field' => 'nid',
+ 'field' => 'nid',
+ 'extra' => array(
+ array('field' => 'uid', 'value' => '***CURRENT_USER***', 'numeric' => TRUE),
+ ),
+ ),
+ );
+
+ $data['history']['timestamp'] = array(
+ 'title' => t('Has new content'),
+ 'field' => array(
+ 'id' => 'history_user_timestamp',
+ 'help' => t('Show a marker if the content is new or updated.'),
+ ),
+ 'filter' => array(
+ 'help' => t('Show only content that is new or updated.'),
+ 'id' => 'history_user_timestamp',
+ ),
+ );
+
+ return $data;
+}
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/js/history.js b/docroot/profiles/discoverdesign/modules/cafnotifications/js/history.js
new file mode 100644
index 0000000..6ce807c
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/js/history.js
@@ -0,0 +1,134 @@
+/**
+ * @file
+ * JavaScript API for the History module, with client-side caching.
+ *
+ * May only be loaded for authenticated users, with the History module enabled.
+ */
+
+(function ($, Drupal, drupalSettings, storage) {
+
+ 'use strict';
+
+ var currentUserID = parseInt(drupalSettings.user.uid, 10);
+
+ // Any comment that is older than 30 days is automatically considered read,
+ // so for these we don't need to perform a request at all!
+ var thirtyDaysAgo = Math.round(new Date().getTime() / 1000) - 30 * 24 * 60 * 60;
+
+ // Use the data embedded in the page, if available.
+ var embeddedLastReadTimestamps = false;
+ if (drupalSettings.history && drupalSettings.history.lastReadTimestamps) {
+ embeddedLastReadTimestamps = drupalSettings.history.lastReadTimestamps;
+ }
+
+ /**
+ * @namespace
+ */
+ Drupal.history = {
+
+ /**
+ * Fetch "last read" timestamps for the given nodes.
+ *
+ * @param {Array} nodeIDs
+ * An array of node IDs.
+ * @param {function} callback
+ * A callback that is called after the requested timestamps were fetched.
+ */
+ fetchTimestamps: function (nodeIDs, callback) {
+ // Use the data embedded in the page, if available.
+ if (embeddedLastReadTimestamps) {
+ callback();
+ return;
+ }
+
+ $.ajax({
+ url: Drupal.url('history/get_node_read_timestamps'),
+ type: 'POST',
+ data: {'node_ids[]': nodeIDs},
+ dataType: 'json',
+ success: function (results) {
+ for (var nodeID in results) {
+ if (results.hasOwnProperty(nodeID)) {
+ storage.setItem('Drupal.history.' + currentUserID + '.' + nodeID, results[nodeID]);
+ }
+ }
+ callback();
+ }
+ });
+ },
+
+ /**
+ * Get the last read timestamp for the given node.
+ *
+ * @param {number|string} nodeID
+ * A node ID.
+ *
+ * @return {number}
+ * A UNIX timestamp.
+ */
+ getLastRead: function (nodeID) {
+ // Use the data embedded in the page, if available.
+ if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
+ return parseInt(embeddedLastReadTimestamps[nodeID], 10);
+ }
+ return parseInt(storage.getItem('Drupal.history.' + currentUserID + '.' + nodeID) || 0, 10);
+ },
+
+ /**
+ * Marks a node as read, store the last read timestamp client-side.
+ *
+ * @param {number|string} nodeID
+ * A node ID.
+ */
+ markAsRead: function (nodeID) {
+ $.ajax({
+ url: Drupal.url('history/' + nodeID + '/read'),
+ type: 'POST',
+ dataType: 'json',
+ success: function (timestamp) {
+ // If the data is embedded in the page, don't store on the client
+ // side.
+ if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
+ return;
+ }
+
+ storage.setItem('Drupal.history.' + currentUserID + '.' + nodeID, timestamp);
+ }
+ });
+ },
+
+ /**
+ * Determines whether a server check is necessary.
+ *
+ * Any content that is >30 days old never gets a "new" or "updated"
+ * indicator. Any content that was published before the oldest known reading
+ * also never gets a "new" or "updated" indicator, because it must've been
+ * read already.
+ *
+ * @param {number|string} nodeID
+ * A node ID.
+ * @param {number} contentTimestamp
+ * The time at which some content (e.g. a comment) was published.
+ *
+ * @return {bool}
+ * Whether a server check is necessary for the given node and its
+ * timestamp.
+ */
+ needsServerCheck: function (nodeID, contentTimestamp) {
+ // First check if the content is older than 30 days, then we can bail
+ // early.
+ if (contentTimestamp < thirtyDaysAgo) {
+ return false;
+ }
+
+ // Use the data embedded in the page, if available.
+ if (embeddedLastReadTimestamps && embeddedLastReadTimestamps[nodeID]) {
+ return contentTimestamp > parseInt(embeddedLastReadTimestamps[nodeID], 10);
+ }
+
+ var minLastReadTimestamp = parseInt(storage.getItem('Drupal.history.' + currentUserID + '.' + nodeID) || 0, 10);
+ return contentTimestamp > minLastReadTimestamp;
+ }
+ };
+
+})(jQuery, Drupal, drupalSettings, window.localStorage);
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/js/mark-as-read.js b/docroot/profiles/discoverdesign/modules/cafnotifications/js/mark-as-read.js
new file mode 100644
index 0000000..e225401
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/js/mark-as-read.js
@@ -0,0 +1,23 @@
+/**
+ * @file
+ * Marks the nodes listed in drupalSettings.history.nodesToMarkAsRead as read.
+ *
+ * Uses the History module JavaScript API.
+ *
+ * @see Drupal.history
+ */
+
+(function (window, Drupal, drupalSettings) {
+
+ 'use strict';
+
+ // When the window's "load" event is triggered, mark all enumerated nodes as
+ // read. This still allows for Drupal behaviors (which are triggered on the
+ // "DOMContentReady" event) to add "new" and "updated" indicators.
+ window.addEventListener('load', function () {
+ if (drupalSettings.history && drupalSettings.history.nodesToMarkAsRead) {
+ Object.keys(drupalSettings.history.nodesToMarkAsRead).forEach(Drupal.history.markAsRead);
+ }
+ });
+
+})(window, Drupal, drupalSettings);
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/src/Controller/HistoryController.php b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Controller/HistoryController.php
new file mode 100644
index 0000000..6a4e80a
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Controller/HistoryController.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Drupal\history\Controller;
+
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Drupal\Core\Controller\ControllerBase;
+use Drupal\node\NodeInterface;
+
+/**
+ * Returns responses for History module routes.
+ */
+class HistoryController extends ControllerBase {
+
+ /**
+ * Returns a set of nodes' last read timestamps.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The request of the page.
+ *
+ * @return Symfony\Component\HttpFoundation\JsonResponse
+ * The JSON response.
+ */
+ public function getNodeReadTimestamps(Request $request) {
+ if ($this->currentUser()->isAnonymous()) {
+ throw new AccessDeniedHttpException();
+ }
+
+ $nids = $request->request->get('node_ids');
+ if (!isset($nids)) {
+ throw new NotFoundHttpException();
+ }
+ return new JsonResponse(history_read_multiple($nids));
+ }
+
+ /**
+ * Marks a node as read by the current user right now.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ * The request of the page.
+ * @param \Drupal\node\NodeInterface $node
+ * The node whose "last read" timestamp should be updated.
+ */
+ public function readNode(Request $request, NodeInterface $node) {
+ if ($this->currentUser()->isAnonymous()) {
+ throw new AccessDeniedHttpException();
+ }
+
+ // Update the history table, stating that this user viewed this node.
+ history_write($node->id());
+
+ return new JsonResponse((int)history_read($node->id()));
+ }
+
+}
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/src/Plugin/views/field/HistoryUserTimestamp.php b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Plugin/views/field/HistoryUserTimestamp.php
new file mode 100644
index 0000000..e6b0548
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Plugin/views/field/HistoryUserTimestamp.php
@@ -0,0 +1,103 @@
+<?php
+
+namespace Drupal\history\Plugin\views\field;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\node\Plugin\views\field\Node;
+
+/**
+ * Field handler to display the marker for new content.
+ *
+ * The handler is named history_user, because of compatibility reasons, the
+ * table is history.
+ *
+ * @ingroup views_field_handlers
+ *
+ * @ViewsField("history_user_timestamp")
+ */
+class HistoryUserTimestamp extends Node {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function usesGroupBy() {
+ return FALSE;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$options = NULL) {
+ parent::init($view, $display, $options);
+
+ if (\Drupal::currentUser()->isAuthenticated()) {
+ $this->additional_fields['created'] = array('table' => 'node_field_data', 'field' => 'created');
+ $this->additional_fields['changed'] = array('table' => 'node_field_data', 'field' => 'changed');
+ if (\Drupal::moduleHandler()->moduleExists('comment') && !empty($this->options['comments'])) {
+ $this->additional_fields['last_comment'] = array('table' => 'comment_entity_statistics', 'field' => 'last_comment_timestamp');
+ }
+ }
+ }
+
+ protected function defineOptions() {
+ $options = parent::defineOptions();
+
+ $options['comments'] = array('default' => FALSE);
+
+ return $options;
+ }
+
+ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
+ parent::buildOptionsForm($form, $form_state);
+ if (\Drupal::moduleHandler()->moduleExists('comment')) {
+ $form['comments'] = array(
+ '#type' => 'checkbox',
+ '#title' => $this->t('Check for new comments as well'),
+ '#default_value' => !empty($this->options['comments']),
+ );
+ }
+ }
+
+ public function query() {
+ // Only add ourselves to the query if logged in.
+ if (\Drupal::currentUser()->isAnonymous()) {
+ return;
+ }
+ parent::query();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render(ResultRow $values) {
+ // Let's default to 'read' state.
+ // This code shadows node_mark, but it reads from the db directly and
+ // we already have that info.
+ $mark = MARK_READ;
+ if (\Drupal::currentUser()->isAuthenticated()) {
+ $last_read = $this->getValue($values);
+ $changed = $this->getValue($values, 'changed');
+
+ $last_comment = \Drupal::moduleHandler()->moduleExists('comment') && !empty($this->options['comments']) ? $this->getValue($values, 'last_comment') : 0;
+
+ if (!$last_read && $changed > HISTORY_READ_LIMIT) {
+ $mark = MARK_NEW;
+ }
+ elseif ($changed > $last_read && $changed > HISTORY_READ_LIMIT) {
+ $mark = MARK_UPDATED;
+ }
+ elseif ($last_comment > $last_read && $last_comment > HISTORY_READ_LIMIT) {
+ $mark = MARK_UPDATED;
+ }
+ $build = array(
+ '#theme' => 'mark',
+ '#status' => $mark,
+ );
+ return $this->renderLink(drupal_render($build), $values);
+ }
+ }
+
+}
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/src/Plugin/views/filter/HistoryUserTimestamp.php b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Plugin/views/filter/HistoryUserTimestamp.php
new file mode 100644
index 0000000..65dfc2b
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Plugin/views/filter/HistoryUserTimestamp.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Drupal\history\Plugin\views\filter;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\views\Plugin\views\filter\FilterPluginBase;
+
+/**
+ * Filter for new content.
+ *
+ * The handler is named history_user, because of compatibility reasons, the
+ * table is history.
+ *
+ * @ingroup views_filter_handlers
+ *
+ * @ViewsFilter("history_user_timestamp")
+ */
+class HistoryUserTimestamp extends FilterPluginBase {
+
+ // Don't display empty space where the operator would be.
+ public $no_operator = TRUE;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function usesGroupBy() {
+ return FALSE;
+ }
+
+ public function buildExposeForm(&$form, FormStateInterface $form_state) {
+ parent::buildExposeForm($form, $form_state);
+ // @todo There are better ways of excluding required and multiple (object flags)
+ unset($form['expose']['required']);
+ unset($form['expose']['multiple']);
+ unset($form['expose']['remember']);
+ }
+
+ protected function valueForm(&$form, FormStateInterface $form_state) {
+ // Only present a checkbox for the exposed filter itself. There's no way
+ // to tell the difference between not checked and the default value, so
+ // specifying the default value via the views UI is meaningless.
+ if ($form_state->get('exposed')) {
+ if (isset($this->options['expose']['label'])) {
+ $label = $this->options['expose']['label'];
+ }
+ else {
+ $label = $this->t('Has new content');
+ }
+ $form['value'] = array(
+ '#type' => 'checkbox',
+ '#title' => $label,
+ '#default_value' => $this->value,
+ );
+ }
+ }
+
+ public function query() {
+ // This can only work if we're authenticated in.
+ if (!\Drupal::currentUser()->isAuthenticated()) {
+ return;
+ }
+
+ // Don't filter if we're exposed and the checkbox isn't selected.
+ if ((!empty($this->options['exposed'])) && empty($this->value)) {
+ return;
+ }
+
+ // Hey, Drupal kills old history, so nodes that haven't been updated
+ // since HISTORY_READ_LIMIT are bzzzzzzzt outta here!
+
+ $limit = REQUEST_TIME - HISTORY_READ_LIMIT;
+
+ $this->ensureMyTable();
+ $field = "$this->tableAlias.$this->realField";
+ $node = $this->query->ensureTable('node_field_data', $this->relationship);
+
+ $clause = '';
+ $clause2 = '';
+ if ($ces = $this->query->ensureTable('comment_entity_statistics', $this->relationship)) {
+ $clause = ("OR $ces.last_comment_timestamp > (***CURRENT_TIME*** - $limit)");
+ $clause2 = "OR $field < $ces.last_comment_timestamp";
+ }
+
+ // NULL means a history record doesn't exist. That's clearly new content.
+ // Unless it's very very old content. Everything in the query is already
+ // type safe cause none of it is coming from outside here.
+ $this->query->addWhereExpression($this->options['group'], "($field IS NULL AND ($node.changed > (***CURRENT_TIME*** - $limit) $clause)) OR $field < $node.changed $clause2");
+ }
+
+ public function adminSummary() {
+ if (!empty($this->options['exposed'])) {
+ return $this->t('exposed');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getCacheMaxAge() {
+ // This filter depends on the current time and therefore is never cacheable.
+ return 0;
+ }
+
+}
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/src/Tests/HistoryTest.php b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Tests/HistoryTest.php
new file mode 100644
index 0000000..17bba34
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Tests/HistoryTest.php
@@ -0,0 +1,148 @@
+<?php
+
+namespace Drupal\history\Tests;
+
+use Drupal\Component\Serialization\Json;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests the History endpoints.
+ *
+ * @group history
+ */
+class HistoryTest extends WebTestBase {
+
+ /**
+ * Modules to enable.
+ *
+ * @var array
+ */
+ public static $modules = array('node', 'history');
+
+ /**
+ * The main user for testing.
+ *
+ * @var object
+ */
+ protected $user;
+
+ /**
+ * A page node for which to check content statistics.
+ *
+ * @var object
+ */
+ protected $testNode;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
+
+ $this->user = $this->drupalCreateUser(array('create page content', 'access content'));
+ $this->drupalLogin($this->user);
+ $this->testNode = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->user->id()));
+ }
+
+ /**
+ * Get node read timestamps from the server for the current user.
+ *
+ * @param array $node_ids
+ * An array of node IDs.
+ *
+ * @return string
+ * The response body.
+ */
+ protected function getNodeReadTimestamps(array $node_ids) {
+ // Build POST values.
+ $post = array();
+ for ($i = 0; $i < count($node_ids); $i++) {
+ $post['node_ids[' . $i . ']'] = $node_ids[$i];
+ }
+
+ // Serialize POST values.
+ foreach ($post as $key => $value) {
+ // Encode according to application/x-www-form-urlencoded
+ // Both names and values needs to be urlencoded, according to
+ // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
+ $post[$key] = urlencode($key) . '=' . urlencode($value);
+ }
+ $post = implode('&', $post);
+
+ // Perform HTTP request.
+ return $this->curlExec(array(
+ CURLOPT_URL => \Drupal::url('history.get_last_node_view', array(), array('absolute' => TRUE)),
+ CURLOPT_POST => TRUE,
+ CURLOPT_POSTFIELDS => $post,
+ CURLOPT_HTTPHEADER => array(
+ 'Accept: application/json',
+ 'Content-Type: application/x-www-form-urlencoded',
+ ),
+ ));
+ }
+
+ /**
+ * Mark a node as read for the current user.
+ *
+ * @param int $node_id
+ * A node ID.
+ *
+ * @return string
+ * The response body.
+ */
+ protected function markNodeAsRead($node_id) {
+ return $this->curlExec(array(
+ CURLOPT_URL => \Drupal::url('history.read_node', array('node' => $node_id), array('absolute' => TRUE)),
+ CURLOPT_HTTPHEADER => array(
+ 'Accept: application/json',
+ ),
+ ));
+ }
+
+ /**
+ * Verifies that the history endpoints work.
+ */
+ function testHistory() {
+ $nid = $this->testNode->id();
+
+ // Retrieve "last read" timestamp for test node, for the current user.
+ $response = $this->getNodeReadTimestamps(array($nid));
+ $this->assertResponse(200);
+ $json = Json::decode($response);
+ $this->assertIdentical(array(1 => 0), $json, 'The node has not yet been read.');
+
+ // View the node.
+ $this->drupalGet('node/' . $nid);
+ $this->assertCacheContext('user.roles:authenticated');
+ // JavaScript present to record the node read.
+ $settings = $this->getDrupalSettings();
+ $libraries = explode(',', $settings['ajaxPageState']['libraries']);
+ $this->assertTrue(in_array('history/mark-as-read', $libraries), 'history/mark-as-read library is present.');
+ $this->assertEqual([$nid => TRUE], $settings['history']['nodesToMarkAsRead'], 'drupalSettings to mark node as read are present.');
+
+ // Simulate JavaScript: perform HTTP request to mark node as read.
+ $response = $this->markNodeAsRead($nid);
+ $this->assertResponse(200);
+ $timestamp = Json::decode($response);
+ $this->assertTrue(is_numeric($timestamp), 'Node has been marked as read. Timestamp received.');
+
+ // Retrieve "last read" timestamp for test node, for the current user.
+ $response = $this->getNodeReadTimestamps(array($nid));
+ $this->assertResponse(200);
+ $json = Json::decode($response);
+ $this->assertIdentical(array(1 => $timestamp), $json, 'The node has been read.');
+
+ // Failing to specify node IDs for the first endpoint should return a 404.
+ $this->getNodeReadTimestamps(array());
+ $this->assertResponse(404);
+
+ // Accessing either endpoint as the anonymous user should return a 403.
+ $this->drupalLogout();
+ $this->getNodeReadTimestamps(array($nid));
+ $this->assertResponse(403);
+ $this->getNodeReadTimestamps(array());
+ $this->assertResponse(403);
+ $this->markNodeAsRead($nid);
+ $this->assertResponse(403);
+ }
+
+}
diff --git a/docroot/profiles/discoverdesign/modules/cafnotifications/src/Tests/Views/HistoryTimestampTest.php b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Tests/Views/HistoryTimestampTest.php
new file mode 100644
index 0000000..0f48401
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafnotifications/src/Tests/Views/HistoryTimestampTest.php
@@ -0,0 +1,89 @@
+<?php
+
+namespace Drupal\history\Tests\Views;
+
+use Drupal\views\Views;
+use Drupal\views\Tests\ViewTestBase;
+
+/**
+ * Tests the history timestamp handlers.
+ *
+ * @group history
+ * @see \Drupal\history\Plugin\views\field\HistoryTimestamp.
+ * @see \Drupal\history\Plugin\views\filter\HistoryTimestamp.
+ */
+class HistoryTimestampTest extends ViewTestBase {
+
+ /**
+ * Modules to enable.
+ *
+ * @var array
+ */
+ public static $modules = array('history', 'node');
+
+ /**
+ * Views used by this test.
+ *
+ * @var array
+ */
+ public static $testViews = array('test_history');
+
+ /**
+ * Tests the handlers.
+ */
+ public function testHandlers() {
+ $nodes = array();
+ $nodes[] = $this->drupalCreateNode();
+ $nodes[] = $this->drupalCreateNode();
+
+ $account = $this->drupalCreateUser();
+ $this->drupalLogin($account);
+ \Drupal::currentUser()->setAccount($account);
+
+ db_insert('history')
+ ->fields(array(
+ 'uid' => $account->id(),
+ 'nid' => $nodes[0]->id(),
+ 'timestamp' => REQUEST_TIME - 100,
+ ))->execute();
+
+ db_insert('history')
+ ->fields(array(
+ 'uid' => $account->id(),
+ 'nid' => $nodes[1]->id(),
+ 'timestamp' => REQUEST_TIME + 100,
+ ))->execute();
+
+
+ $column_map = array(
+ 'nid' => 'nid',
+ );
+
+ // Test the history field.
+ $view = Views::getView('test_history');
+ $view->setDisplay('page_1');
+ $this->executeView($view);
+ $this->assertEqual(count($view->result), 2);
+ $output = $view->preview();
+ $this->setRawContent(\Drupal::service('renderer')->renderRoot($output));
+ $result = $this->xpath('//span[@class=:class]', array(':class' => 'marker'));
+ $this->assertEqual(count($result), 1, 'Just one node is marked as new');
+
+ // Test the history filter.
+ $view = Views::getView('test_history');
+ $view->setDisplay('page_2');
+ $this->executeView($view);
+ $this->assertEqual(count($view->result), 1);
+ $this->assertIdenticalResultset($view, array(array('nid' => $nodes[0]->id())), $column_map);
+
+ // Install Comment module and make sure that content types without comment
+ // field will not break the view.
+ // See \Drupal\history\Plugin\views\filter\HistoryUserTimestamp::query()
+ \Drupal::service('module_installer')->install(['comment']);
+ $view = Views::getView('test_history');
+ $view->setDisplay('page_2');
+ $this->executeView($view);
+
+ }
+
+}
diff --git a/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.module b/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.module
index b29a5d3..3cb69ce 100644
--- a/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.module
+++ b/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.module
@@ -367,10 +367,15 @@ function cafprojectedit_entity_extra_field_info() {
* @return array
*/
function cafprojectedit_image_styles_for_entity(FieldableEntityInterface $entity) {
+ /**
+ * @var FieldDefinitionInterface[] $definitions
+ * contains only image and entity_reference fields.
+ */
$definitions = array_filter($entity->getFieldDefinitions(), function (FieldDefinitionInterface $definition) {
return $definition->getType() === 'image' || $definition->getType() === 'entity_reference';
});
+ /** @var array $fields */
$fields = array_map(function (FieldDefinitionInterface $definition) use ($entity) {
return $entity->get($definition->getName());
}, $definitions);
diff --git a/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.routing.yml b/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.routing.yml
index 2b4015e..0659ca8 100644
--- a/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.routing.yml
+++ b/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.routing.yml
@@ -55,6 +55,15 @@ cafprojectedit.toggle_status:
_entity_access: node.update
js: 'nojs|ajax'
+#cafprojectedit.deactivate:
+# path: '/node/{node}/{js}/workflow/{to_sid}'
+# defaults:
+# _controller: 'cafprojectedit.controller.workflow:state'
+# to_sid: project_archived
+# requirements:
+# _entity_access: node.update
+# js: 'nojs|ajax'
+
cafprojectedit.deactivate_confirm:
path: '/node/{node}/state/{workflow_state}'
defaults:
diff --git a/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.services.yml b/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.services.yml
index bb976f6..3ffa73a 100644
--- a/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.services.yml
+++ b/docroot/profiles/discoverdesign/modules/cafprojectedit/cafprojectedit.services.yml
@@ -30,3 +30,7 @@ services:
arguments: ['@queue', '@cafprojectedit.node_storage']
tags:
- { name: event_subscriber }
+
+# cafprojectedit.controller.workflow:
+# class: Drupal\cafprojectedit\Controller\WorkflowController
+# arguments: []
diff --git a/docroot/profiles/discoverdesign/modules/cafteachers/Tests/Controller/StudentsControllerTest.php b/docroot/profiles/discoverdesign/modules/cafteachers/Tests/Controller/StudentsControllerTest.php
new file mode 100644
index 0000000..2b2e9c4
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafteachers/Tests/Controller/StudentsControllerTest.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Drupal\cafteachers\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Provides automated tests for the cafteachers module.
+ */
+class StudentsControllerTest extends WebTestBase {
+ /**
+ * {@inheritdoc}
+ */
+ public static function getInfo() {
+ return array(
+ 'name' => "cafteachers StudentsController's controller functionality",
+ 'description' => 'Test Unit for module cafteachers and controller StudentsController.',
+ 'group' => 'Other',
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setUp() {
+ parent::setUp();
+ }
+
+ /**
+ * Tests cafteachers functionality.
+ */
+ public function testStudentsController() {
+ // Check that the basic functions of module cafteachers.
+ $this->assertEquals(TRUE, TRUE, 'Test Unit Generated via App Console.');
+ }
+
+}
diff --git a/docroot/profiles/discoverdesign/modules/cafteachers/src/Controller/StudentsController.php b/docroot/profiles/discoverdesign/modules/cafteachers/src/Controller/StudentsController.php
new file mode 100644
index 0000000..c7c006f
--- /dev/null
+++ b/docroot/profiles/discoverdesign/modules/cafteachers/src/Controller/StudentsController.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Drupal\cafteachers\Controller;
+
+use Drupal\Core\Controller\ControllerBase;
+use Drupal\user\UserInterface;
+
+/**
+ * Class StudentsController.
+ *
+ * @package Drupal\cafteachers\Controller
+ */
+class StudentsController extends ControllerBase {
+ /**
+ * Index.
+ *
+ * @return string
+ * Return Hello string.
+ */
+ public function index(UserInterface $user) {
+
+
+ return [
+ '#type' => 'markup',
+ '#markup' => $this->t('Implement method: index with parameter(s): $user'),
+ ];
+ }
+
+}
diff --git a/docroot/profiles/discoverdesign/src/Routing/ClassRouteSubscriber.php b/docroot/profiles/discoverdesign/src/Routing/ClassRouteSubscriber.php
index 0884a12..cad7926 100644
--- a/docroot/profiles/discoverdesign/src/Routing/ClassRouteSubscriber.php
+++ b/docroot/profiles/discoverdesign/src/Routing/ClassRouteSubscriber.php
@@ -19,7 +19,7 @@ class ClassRouteSubscriber extends RouteSubscriberBase {
protected function alterRoutes(RouteCollection $collection) {
$collection->get('view.classes.page_1')->setOption('_admin_route', TRUE);
$collection->get('view.classes.page_2')->setOption('_admin_route', TRUE);
- $collection->get('view.roster.page_1')->setOption('_admin_route', TRUE);
+// $collection->get('view.roster.page_1')->setOption('_admin_route', TRUE);
$collection->get('entity.badging.canonical')->setOption('_admin_route', TRUE);
}
}
diff --git a/docroot/profiles/discoverdesign/themes/newel/templates/block/block--newel-account-menu.html.twig b/docroot/profiles/discoverdesign/themes/newel/templates/block/block--newel-account-menu.html.twig
index 23f9f65..fd4c805 100644
--- a/docroot/profiles/discoverdesign/themes/newel/templates/block/block--newel-account-menu.html.twig
+++ b/docroot/profiles/discoverdesign/themes/newel/templates/block/block--newel-account-menu.html.twig
@@ -1,5 +1,6 @@
<div{{ attributes.addClass('user-info') }}>
+ {{ title_prefix }}
{% if user.isAuthenticated %}
<div class="dropdown">
<span class="trigger">
@@ -15,4 +16,5 @@
{% else %}
{{ content }}
{% endif %}
+ {{ title_suffix }}
</div>
\ No newline at end of file
diff --git a/docroot/profiles/discoverdesign/themes/newel/templates/block/block--newel-branding.html.twig b/docroot/profiles/discoverdesign/themes/newel/templates/block/block--newel-branding.html.twig
index 71c8a49..9bf1cf6 100644
--- a/docroot/profiles/discoverdesign/themes/newel/templates/block/block--newel-branding.html.twig
+++ b/docroot/profiles/discoverdesign/themes/newel/templates/block/block--newel-branding.html.twig
@@ -1,3 +1,4 @@
+{% extends "block.html.twig" %}
{#
/**
* @file
@@ -12,6 +13,7 @@
* - site_slogan: Slogan for site as defined in Site information settings.
*/
#}
+{% block content %}
<div{{ attributes.addClass('site-logo') }}>
{% if site_logo %}
<a href="{{ path('<front>') }}" title="{{ 'Home'|t }}" rel="home">
@@ -23,3 +25,4 @@
{% endif %}
{{ site_slogan }}
</div>
+{% endblock %}
\ No newline at end of file
diff --git a/styleguide b/styleguide
index 74d9ade..a6fec0c 160000
--- a/styleguide
+++ b/styleguide
@@ -1 +1 @@
-Subproject commit 74d9adea14168e5d2d91c0d07c567cc6af2e1f46
+Subproject commit a6fec0c1e3115aeb1be4f69c77f88e71243aca9d
diff --git a/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php
index 29da4ab..d6ed359 100644
--- a/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php
+++ b/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php
@@ -154,6 +154,7 @@ class FileProfilerStorage implements ProfilerStorageInterface
'method' => $profile->getMethod(),
'url' => $profile->getUrl(),
'time' => $profile->getTime(),
+ 'status_code' => $profile->getStatusCode(),
);
if (false === file_put_contents($file, serialize($data))) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment