Commit 66f7334c authored by mathieso's avatar mathieso

More views plugins.

parent 0094d7e5
......@@ -2815,6 +2815,7 @@ function skilling_theme($existing, $type, $theme, $path) {
'submission_links' => NULL,
'show_exercise_link' => NULL,
'submission_status' => NULL,
'is_student' => NULL,
],
],
'insert_pattern' => [
......
......@@ -38,6 +38,36 @@ function skilling_views_data_alter(&$data) {
],
];
// Show whether an exercise is required.
$data['views']['is_exercise_required'] = [
'title' => t('Is exercise required?'),
'help' => t('Creates a field showing whether an exercise is required.'),
'group' => 'Skilling',
'field' => [
'id' => 'is_exercise_required',
],
];
// Show whether an exercise is required.
$data['views']['exercise_due_date'] = [
'title' => t('Exercise due date'),
'help' => t('Date an exercise is due.'),
'group' => 'Skilling',
'field' => [
'id' => 'exercise_due_date',
],
];
// Max submissions allowed for an exercise.
$data['views']['max_submissions'] = [
'title' => t('Max submissions allowed for an exercise'),
'help' => t('Maximum submissions of allowed for an exercise.'),
'group' => 'Skilling',
'field' => [
'id' => 'max_submissions',
],
];
// Really a filter.
$data['views']['instructor_of_node_owner'] = [
'title' => t('Current user is instructor of node owner'),
......
......@@ -2,10 +2,15 @@
namespace Drupal\skilling\Plugin\Block;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Render\Renderer;
use Drupal\Core\Session\AccountInterface;
use Drupal\skilling\CurrentClass;
use Drupal\skilling\SkillingConstants;
use Drupal\skilling\SkillingCurrentUser;
use Drupal\skilling\SkillingUserFactory;
use Drupal\skilling\Timeline;
use Drupal\skilling\Utilities;
use Symfony\Component\DependencyInjection\ContainerInterface;
......@@ -37,6 +42,27 @@ class TimelineBlock extends BlockBase implements ContainerFactoryPluginInterface
/** @var \Drupal\skilling\Utilities */
protected $utilities;
/**
* The user factory service.
*
* @var \Drupal\skilling\SkillingUserFactory
*/
protected $userFactory;
/**
* The Skilling current user service.
*
* @var \Drupal\skilling\SkillingCurrentUser
*/
protected $skillingCurrentUser;
/**
* The current class service.
*
* @var \Drupal\skilling\CurrentClass
*/
protected $currentClass;
/**
* Constructs a new CalendarBlock object.
*
......@@ -53,11 +79,19 @@ class TimelineBlock extends BlockBase implements ContainerFactoryPluginInterface
* @param \Drupal\skilling\Utilities $utilities
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition,
Renderer $renderer, Timeline $timelineService, Utilities $utilities) {
Renderer $renderer,
Timeline $timelineService,
Utilities $utilities,
CurrentClass $current_class,
SkillingUserFactory $userFactory,
SkillingCurrentUser $skillingCurrentUser) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->renderer = $renderer;
$this->timelineService = $timelineService;
$this->utilities = $utilities;
$this->currentClass = $current_class;
$this->userFactory = $userFactory;
$this->skillingCurrentUser = $skillingCurrentUser;
}
/**
......@@ -71,10 +105,36 @@ class TimelineBlock extends BlockBase implements ContainerFactoryPluginInterface
$plugin_definition,
$container->get('renderer'),
$container->get('skilling.timeline'),
$container->get('skilling.utilities')
$container->get('skilling.utilities'),
$container->get('skilling.current_class'),
$container->get('skilling.skilling_user_factory'),
$container->get('skilling.skilling_current_user')
);
}
/**
* Only show for students.
*
* @param \Drupal\Core\Session\AccountInterface $account
* @param bool $return_as_object
*
* @return bool|\Drupal\Core\Access\AccessResult|\Drupal\Core\Access\AccessResultAllowed|\Drupal\Core\Access\AccessResultForbidden|\Drupal\Core\Access\AccessResultInterface
*/
public function access(AccountInterface $account, $return_as_object = FALSE) {
if ($account->isAnonymous()) {
return AccessResult::forbidden();
}
// Hide block if not a current class.
$canShow = FALSE;
if (!is_null($this->currentClass->getCurrentClass())) {
$canShow = TRUE;
}
if ($canShow) {
return AccessResult::allowed();
}
return AccessResult::forbidden();
}
/**
* {@inheritdoc}
*
......
......@@ -233,18 +233,20 @@ class ExerciseTag extends SkillingCustomTagBase {
$moduleUrl = $this->skillingUtilities->getModuleUrlPath();
$challengeImageUrl = $moduleUrl . 'images/challenge.png';
// Get data from the class about due date, required, etc.
// Only makes sense if there is a current class.
// Only makes sense if there is a current class, and the user is a student.
$isRequiredDisplay = null;
$exerciseMaxSubsDisplay = null;
$whenDueDisplay = null;
$numberOfSubmissions = null;
$exerciseSubmissionStatus = null;
if (!is_null($this->currentClass->getCurrentClass())) {
// Submissions from the user.
$exerciseSubmissionStatus = $this->submissionsService->getSubmissionStatusForStudentExercise(
$this->currentUser, $exerciseId, $this->currentClass
);
$numberOfSubmissions = count($renderableSubmissionLinks['submissions']);
if ($this->currentUser->isStudent()) {
// Submissions from the user.
$exerciseSubmissionStatus = $this->submissionsService->getSubmissionStatusForStudentExercise(
$this->currentUser, $exerciseId, $this->currentClass
);
$numberOfSubmissions = count($renderableSubmissionLinks['submissions']);
}
$exerciseDue = $this->currentClass->getExerciseDueForExercise($exerciseId);
if (is_null($exerciseDue)) {
// Exercise not in class timeline.
......@@ -301,6 +303,7 @@ class ExerciseTag extends SkillingCustomTagBase {
'#submission_links' => $renderableSubmissionLinks,
'#show_exercise_link' => $showExerciseLink ? 'yes' : 'no',
'#submission_status' => $exerciseSubmissionStatus,
'#is_student' => $this->currentUser->isStudent(),
'#cache' => [
'max-age' => 0,
],
......
<?php
namespace Drupal\skilling\Plugin\views\field;
use DateInterval;
use DateTime;
use Drupal;
use Drupal\skilling\SkillingConstants;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;
/**
* A field showing an exercise's due date.
*
* @ingroup views_field_handlers
*
* @ViewsField("exercise_due_date")
*/
class ExerciseDueDate extends FieldPluginBase {
/**
* {@inheritdoc}
*/
public function usesGroupBy() {
return FALSE;
}
/**
* {@inheritdoc}
*/
public function query() {
// Do nothing -- to override the parent query.
}
/**
* {@inheritdoc}
*
* @param \Drupal\views\ResultRow $row
*
* @return \Drupal\Core\StringTranslation\TranslatableMarkup|string
* @throws \Exception
*/
public function render(ResultRow $row) {
// Default if exercise not in class, or no current class.
$result = $this->t('N/A');
$exercise = $row->_entity;
// Is it an exercise?
if ($exercise->bundle() === SkillingConstants::EXERCISE_CONTENT_TYPE) {
/** @var Drupal\skilling\CurrentClass $currentClass */
$currentClass = Drupal::service('skilling.current_class');
if (!is_null($currentClass->getCurrentClass())) {
$exerciseDueData
= $currentClass->getExerciseDueForExercise($exercise->id());
if (!is_null($exerciseDueData)) {
/** @var Drupal\skilling\Utilities $utilities */
$utilities = Drupal::service('skilling.utilities');
$classStartDate = $currentClass->getStartDate();
$classStartDate = new DateTime($classStartDate);
$dayExerDue = $exerciseDueData['day'] - 1;
$result = $utilities->getCalendarDateFromDayOffset(
$classStartDate,
$dayExerDue
);
}
}
}
return $result;
/** @var \Drupal\node\Entity\Node $class */
$class = $values->_entity;
$classStartDate = $class->field_when_starts->value;
$classStartDate = new DateTime($classStartDate);
// Get the day offset the event happens.
/** @var \Drupal\paragraphs\ParagraphInterface $calendarEvent */
$calendarEvent = $values->_relationship_entities['field_calendar_events'];
$eventDayOffset = $calendarEvent->field_day->value;
// Compute the event date.
$eventDate = clone $classStartDate;
$eventDate->add(new DateInterval('P' . $eventDayOffset . 'D'));
// Format the event date.
$dateFormat = 'D, M j, Y';
$eventDateFormatted = $eventDate->format($dateFormat);
return $eventDateFormatted;
}
}
<?php
namespace Drupal\skilling\Plugin\views\field;
use DateInterval;
use DateTime;
use Drupal\skilling\SkillingConstants;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;
/**
* A field showing whether an exercise is required.
*
* @ingroup views_field_handlers
*
* @ViewsField("is_exercise_required")
*/
class IsExerciseRequired extends FieldPluginBase {
/**
* {@inheritdoc}
*/
public function usesGroupBy() {
return FALSE;
}
/**
* {@inheritdoc}
*/
public function query() {
// Do nothing -- to override the parent query.
}
/**
* {@inheritdoc}
*/
// protected function defineOptions() {
// $options = parent::defineOptions();
//
// $options['hide_alter_empty'] = ['default' => FALSE];
// return $options;
// }
/**
* {@inheritdoc}
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\skilling\Exception\SkillingValueMissingException
* @throws \Drupal\skilling\Exception\SkillingWrongTypeException
* @throws \Drupal\skilling\Exception\SkillingException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Exception
*/
public function render(ResultRow $row) {
// Default if exercise not in class, or no current class.
$result = $this->t('N/A');
$exercise = $row->_entity;
// Is it an exercise?
if ($exercise->bundle() === SkillingConstants::EXERCISE_CONTENT_TYPE) {
$currentClass = \Drupal::service('skilling.current_class');
if (!is_null($currentClass->getCurrentClass())) {
$exerciseDueData
= $currentClass->getExerciseDueForExercise($exercise->id());
if (!is_null($exerciseDueData)) {
$isRequired = $exerciseDueData['required'];
$result = $isRequired
? (string) $this->t('Yes')
: (string) $this->t('No');
}
}
}
return $result;
}
}
<?php
namespace Drupal\skilling\Plugin\views\field;
use DateInterval;
use DateTime;
use Drupal\skilling\SkillingConstants;
use Drupal\views\Plugin\views\field\FieldPluginBase;
use Drupal\views\ResultRow;
/**
* A field showing the max submissions allowed for an exercise.
*
* @ingroup views_field_handlers
*
* @ViewsField("max_submissions")
*/
class MaxSubmissions extends FieldPluginBase {
/**
* {@inheritdoc}
*/
public function usesGroupBy() {
return FALSE;
}
/**
* {@inheritdoc}
*/
public function query() {
// Do nothing -- to override the parent query.
}
/**
* {@inheritdoc}
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\skilling\Exception\SkillingValueMissingException
* @throws \Drupal\skilling\Exception\SkillingWrongTypeException
* @throws \Drupal\skilling\Exception\SkillingException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
* @throws \Exception
*/
public function render(ResultRow $row) {
// Default if exercise not in class, or no current class.
$result = $this->t('N/A');
$exercise = $row->_entity;
// Is it an exercise?
if ($exercise->bundle() === SkillingConstants::EXERCISE_CONTENT_TYPE) {
$currentClass = \Drupal::service('skilling.current_class');
if (!is_null($currentClass->getCurrentClass())) {
$exerciseDueData
= $currentClass->getExerciseDueForExercise($exercise->id());
$maxSubsGiven = isset($exerciseDueData['maxSubs'])
&& is_numeric($exerciseDueData['maxSubs']);
if ($maxSubsGiven) {
$result = $exerciseDueData['maxSubs'];
}
}
}
return $result;
}
}
......@@ -171,19 +171,29 @@ class SkillingClass {
if (isset($dayDataieThing[0])) {
$day = (int) $exerciseDueParagraph->get(SkillingConstants::FIELD_DAY)
->getValue()[0]['value'];
$required = (boolean) $exerciseDueParagraph->get(SkillingConstants::FIELD_REQUIRED)
->getValue()[0]['value'];
$required = FALSE;
if (isset($exerciseDueParagraph->get(SkillingConstants::FIELD_REQUIRED)
->getValue()[0]['value'])) {
$required = (boolean) $exerciseDueParagraph->get(SkillingConstants::FIELD_REQUIRED)
->getValue()[0]['value'];
// Convert from truthy/falsey to real bool.
$required = !(!$required);
}
// Compute max subs allowed for exercise.
$exerMaxSubs = $exerciseDueParagraph->get(SkillingConstants::FIELD_MAX_SUBMISSIONS)
// Start with value from class.
$exerMaxSubs = (integer)$class->get(SkillingConstants::FIELD_DEFAULT_MAX_SUBMISSIONS)
->getValue()[0]['value'];
if (is_null($exerMaxSubs)) {
$exerMaxSubs = $class->get(SkillingConstants::FIELD_DEFAULT_MAX_SUBMISSIONS)
if (isset($exerciseDueParagraph->get(SkillingConstants::FIELD_MAX_SUBMISSIONS)
->getValue()[0]['value'])) {
$exerMaxSubs = $exerciseDueParagraph->get(SkillingConstants::FIELD_MAX_SUBMISSIONS)
->getValue()[0]['value'];
if (!$exerMaxSubs) {
$exerMaxSubs = 0;
}
else {
$exerMaxSubs = (integer) $exerMaxSubs;
}
}
else {
$exerMaxSubs = (integer) $exerMaxSubs;
}
// nulll or "2"
$exerciseDue = [
'exerciseId' => $exerciseId,
'day' => $day,
......
......@@ -2,6 +2,7 @@
namespace Drupal\skilling;
use DateInterval;
use DateTime;
use Drupal\Core\Messenger\Messenger;
use Drupal\Core\Routing\CurrentRouteMatch;
......@@ -974,4 +975,31 @@ class Utilities {
return $result;
}
/**
* Compute date to display, given date and days offset.
*
* @param \DateTime $startDate
* Start date
* @param $offset
* Offset in days
* @param string $dateFormat
* How to format date, defaults to 'D, M j, Y'.
*
* @return string
* Formatted date.
*
* @throws \Exception
*/
public function getCalendarDateFromDayOffset(
DateTime $startDate,
$offset,
$dateFormat = 'D, M j, Y') {
$eventDate = clone $startDate;
$eventDate->add(new DateInterval('P' . $offset . 'D'));
// Format the date.
$eventDateFormatted = $eventDate->format($dateFormat);
return $eventDateFormatted;
}
}
......@@ -47,7 +47,7 @@
title="{{ 'Is this exercise required?'|t }}"
>{{ 'Required:'|t }} {{ required }}</span>
{% endif %}
{% if number_subs is not null %}
{% if is_student and number_subs is not null %}
<span
class="skilling-num-subs"
title="{{ 'Have many times you have tried this exercise so far.'|t }}"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment