Skip to content

Commit

Permalink
Merge branch 'main' into setup_cloud
Browse files Browse the repository at this point in the history
  • Loading branch information
IDzyre committed Aug 8, 2023
2 parents 31b0512 + 8e6731f commit edc452f
Show file tree
Hide file tree
Showing 16 changed files with 244 additions and 49 deletions.
15 changes: 13 additions & 2 deletions site/app/controllers/MiscController.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,6 @@ public function downloadSubmissionZip($gradeable_id, $user_id, $version, $is_ano
$options->setSendHttpHeaders(true);
$options->setEnableZip64(false);

//TODO: In here for notebooks remove the server-generated answers
// create a new zipstream object
$zip_stream = new \ZipStream\ZipStream($zip_file_name, $options);
foreach ($folder_names as $folder_name) {
Expand All @@ -432,7 +431,19 @@ public function downloadSubmissionZip($gradeable_id, $user_id, $version, $is_ano
}
$file_path = $file->getRealPath();
$relative_path = substr($file_path, strlen($path) + 1);
if ($this->core->getAccess()->canI("path.read", ["dir" => $folder_name, "path" => $file_path, "gradeable" => $gradeable, "graded_gradeable" => $graded_gradeable, "gradeable_version" => $gradeable_version->getVersion()])) {
if (
$this->core->getAccess()->canI(
"path.read",
[
"dir" => $folder_name,
"path" => $file_path,
"gradeable" => $gradeable,
"graded_gradeable" => $graded_gradeable,
"gradeable_version" => $gradeable_version->getVersion(),
"root_path" => $path
]
)
) {
$zip_stream->addFileFromPath(FileUtils::joinPaths($folder_name, $relative_path), $file_path);
}
}
Expand Down
44 changes: 42 additions & 2 deletions site/app/controllers/calendar/CalendarController.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,52 @@ public function viewCalendar(): WebResponse {

$courses = $this->core->getQueries()->getCourseForUserId($user->getId());

$gradeables_of_user = GradeableUtils::getAllGradeableListFromUserId($this->core, $user, $courses, $calendar_messages);
//Check if should see all courses
$show_all_courses = '1';
if (isset($_COOKIE['calendar_show_all'])) { //Check if show_all cookie exists
$show_all_courses = $_COOKIE['calendar_show_all'];
}
else { //No cookie, create cookie
setcookie('calendar_show_all', '1', time() + (10 * 365 * 24 * 60 * 60));
$show_all_courses = '1';
}

$filtered_courses = [];
if ($show_all_courses === '1') {
$filtered_courses = $courses;
}
else {
//If can't see all courses, see specific course
if (isset($_COOKIE['calendar_course'])) { //if cookie exists, find matching course
$found_course = false;
foreach ($courses as $course) {
$course_string = sprintf("%s %s", $course->getTitle(), $course->getTerm());
if ($course_string === $_COOKIE['calendar_course']) {
$found_course = true;
array_push($filtered_courses, $course);
break;
}
}
if (!$found_course) { //If can't find course, default to first course
$course_cookie_value = sprintf("%s %s", $courses[1]->getTitle(), $courses[1]->getTerm());
setcookie('calendar_course', $course_cookie_value, time() + (10 * 365 * 24 * 60 * 60));
array_push($filtered_courses, $courses[1]);
}
}
else { //if cookie doesn't exist, choose first course
$course_cookie_value = sprintf("%s %s", $courses[1]->getTitle(), $courses[1]->getTerm());
setcookie('calendar_course', $course_cookie_value, time() + (10 * 365 * 24 * 60 * 60));
array_push($filtered_courses, $courses[1]);
}
}

$gradeables_of_user = GradeableUtils::getAllGradeableListFromUserId($this->core, $user, $filtered_courses, $calendar_messages);

return new WebResponse(
CalendarView::class,
'showCalendar',
CalendarInfo::loadGradeableCalendarInfo($this->core, $gradeables_of_user, $courses, $calendar_messages)
CalendarInfo::loadGradeableCalendarInfo($this->core, $gradeables_of_user, $filtered_courses, $calendar_messages),
$courses
);
}

Expand Down
5 changes: 5 additions & 0 deletions site/app/libraries/Access.php
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,11 @@ public function canUser($user, string $action, $args) {
return false;
}

//Make sure notebook generated files can't be accessed
if (self::checkBits($checks, self::CHECK_STUDENT_DOWNLOAD) && array_key_exists("root_path", $args)) {
return $gradeable->canStudentDownloadFile($args["gradeable_version"], $args["path"], $args["root_path"]);
}

//As these are not grading-related they can return false immediately
if ($group === User::GROUP_STUDENT) {
if (self::checkBits($checks, self::CHECK_STUDENT_VIEW)) {
Expand Down
2 changes: 1 addition & 1 deletion site/app/libraries/database/DatabaseQueries.php
Original file line number Diff line number Diff line change
Expand Up @@ -2796,7 +2796,7 @@ public function getUsersByRotatingSections($sections, $orderBy = "rotating_secti
* @return array
*/
public function getRegistrationSections() {
$this->course_db->query("SELECT * FROM sections_registration ORDER BY SUBSTRING(sections_registration_id, '^[^0-9]*'), COALESCE(SUBSTRING(sections_registration_id, '[0-9]+')::INT, -1), SUBSTRING(sections_registration_id, '[^0-9]*$') ");
$this->course_db->query("SELECT * FROM sections_registration ORDER BY SUBSTRING(sections_registration_id, '^[^0-9]*'), COALESCE(SUBSTRING(sections_registration_id, '[0-9]+')::NUMERIC, -1), SUBSTRING(sections_registration_id, '[^0-9]*$') ");
return $this->course_db->rows();
}

Expand Down
10 changes: 10 additions & 0 deletions site/app/models/CalendarInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,20 @@ public static function loadGradeableCalendarInfo(Core $core, array $gradeables_o
return $info;
}

/**
* @return array<string, array<string,bool|string>>>
*/
public function getItemsByDate(): array {
return $this->items_by_date;
}

/**
* @return array<string, array<string,bool|string>>>
*/
public function getItemsByDateInCourses(): array {
return $this->items_by_date;
}

public function getItemsBySections(): array {
return $this->items_by_sections;
}
Expand Down
3 changes: 2 additions & 1 deletion site/app/models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -632,8 +632,9 @@ public static function validateUserData($field, $data): bool {
return preg_match("~^[1-4]{1}$~", $data) === 1;
case 'registration_section':
//Registration section must contain only alpha (upper and lower permitted), numbers, underscores, hyphens.
// AND between 0 and 20 chars.
//"NULL" registration section should be validated as a datatype, not as a string.
return preg_match("~^(?!^null$)[a-z0-9_\-]+$~i", $data) === 1 || is_null($data);
return preg_match("~^(?!^null$)[a-z0-9_\-]{1,20}$~i", $data) === 1 || is_null($data);
case 'course_section_id':
//Course Section Id section must contain only alpha (upper and lower permitted), numbers, underscores, hyphens.
return preg_match("~^(?!^null$)[a-z0-9_\-]+$~i", $data) === 1 || is_null($data);
Expand Down
48 changes: 48 additions & 0 deletions site/app/models/gradeable/Gradeable.php
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,54 @@ public function canStudentDownload() {
return $this->student_download;
}

/**
* Determines if a specific file can be downloaded by a student (Used to determine access for zip download)
* @param int $version which version of the gradeable is this file in?
* @param string $file_path the path of the file that client is trying to download
* @param string $root_path the root path of the gradeable files
* @return bool
*/
public function canStudentDownloadFile(int $version, string $file_path, string $root_path): bool {
if (!$this->student_download) {
return false;
}
//get the folder it is contained in
$path_array = explode("/", $file_path);
$outside_folder = $path_array[count($path_array) - 2];
$file_name = $path_array[count($path_array) - 1];
//Automatically remove these special files
if (
$file_name === ".submit.timestamp"
|| $file_name === ".submit.notebook"
|| $file_name === ".user_assignment_access.json"
) {
return false;
}

$autograding_config = $this->getAutogradingConfig();
if ($autograding_config->isNotebookGradeable()) {
//Get notebook data to get list of notebook filenames
$notebook_model = $autograding_config->getUserSpecificNotebook($this->core->getUser()->getId());
$notebook = $notebook_model->getNotebook();
$notebook_data = $notebook_model->getMostRecentNotebookSubmissions(
$version,
$notebook,
$this->core->getUser()->getId(),
$version,
$this->getId()
);

//get the root folder
$root_path_array = explode("/", $root_path);
$root_folder = $path_array[count($root_path_array) - 1];
//all notebook generated submissions reside in the root folder
if ($outside_folder === $root_folder) {
return false;
}
}
return true;
}

/**
* Gets if this gradeable is defined as a "bulk upload" gradeable (if students are only allowed to view it after
* grades are released)
Expand Down
5 changes: 3 additions & 2 deletions site/app/templates/admin/users/RotatingSectionsForm.twig
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@
<span class="option-title">Add Registration Section</span>
<br>
<span class="option-alt">
Enter a registration section which is not already a registration section.
</span>
<strong>Format:</strong> Alphanumeric (a-z, A-Z, 0-9), underscores, hyphens, with no space and maximum 20 characters.<br>
Enter a registration section which is not already a registration section.
</span>
</label>
</div>
</div>
Expand Down
42 changes: 33 additions & 9 deletions site/app/templates/calendar/Calendar.twig
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,40 @@
$( document ).ready(function() {
// Get value of the type dropdown
const type = $("#calendar-item-type-edit").val();
loadCalendar(curr_month, curr_year, curr_day, type);
// Get cookie for curr the viewed day, month, and year
cookie_year = parseInt(Cookies.get('calendar_year'));
cookie_month = parseInt(Cookies.get('calendar_month'));
cookie_day = parseInt(Cookies.get('calendar_day'));
if (isNaN(cookie_year)) {
cookie_year = curr_year;
}
if (isNaN(cookie_month)) {
cookie_month = curr_month;
}
if (isNaN(cookie_day)) {
cookie_day = curr_day;
}
// Load the calendar to the correct day
loadCalendar(cookie_month, cookie_year, cookie_day, type);
});
function changeView(x) {
if (x.value === "month") {
document.cookie = "view=month";
Cookies.set('view',x.value);
cookie_year = parseInt(Cookies.get('calendar_year'));
cookie_month = parseInt(Cookies.get('calendar_month'));
cookie_day = parseInt(Cookies.get('calendar_day'));
if (isNaN(cookie_year)) {
cookie_year = view_year;
}
else if (x.value === "two_week") {
document.cookie = "view=two_week";
if (isNaN(cookie_month)) {
cookie_month = view_month;
}
else if (x.value === "one_week") {
document.cookie = "view=one_week";
if (isNaN(cookie_day)) {
cookie_day = view_day;
}
loadCalendar({{ view_month }}, {{ view_year }}, {{ curr_day }}, x.value);
// Load the calendar to the correct day
loadCalendar(cookie_month, cookie_year, cookie_day, x.value);
}
</script>

Expand All @@ -38,7 +58,10 @@
<i class="fas fa-plus"></i> New Item
</button>
{% endif %}


<button type="button" onclick="openOptionsModal()" class="btn btn-primary">
<i class="fas fa-sliders"></i> Options
</button>
<select id="calendar-item-type-edit" name="type" onchange="changeView(this);">
<option value="month" {% if (view_cookie is defined) and view_cookie == "month" %} selected {% endif %}>Month</option>
<option value="two_week" {% if (view_cookie is defined) and view_cookie == "two_week" %} selected {% endif %}>Two Week</option>
Expand Down Expand Up @@ -99,3 +122,4 @@

{{ include('calendar/NewCalendarItem.twig') }}
{{ include('calendar/EditCalendarItem.twig') }}
{{ include('calendar/CalendarOptions.twig') }}
18 changes: 18 additions & 0 deletions site/app/templates/calendar/CalendarOptions.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% extends 'generic/Popup.twig' %}
{% block popup_id %}calendar-options-form{% endblock %}
{% block title %}Calendar Options{% endblock %}
{% block body %}
<label for="filter-courses-menu">Select Course: </label>
<select name="filter-courses-menu" id="filter-courses-menu">
{% if course_names|length > 1 %}
<option value="show all">All Courses</option>
{% endif %}
{% for course in course_names %}
<option value="{{course}}">{{course}}</option>
{% endfor %}
</select>
{% endblock %}
{% block buttons %}
{{ block('close_button') }}
<input name="submit" class="btn btn-primary key_to_click" type="submit" value="Submit" onclick="updateCalendarFilters()"/>
{% endblock %}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
<div class="row">
<div class="box col-md-6" id="submitted-files">
{% for file in files %}
{% if not (file.name in notebook) %}
{# In a notebook, files in the root directory are server-generated. If not a notebook, all files can be seen #}
{% if (is_notebook and (file.relative_name|split('/'))|length > 1) or (not is_notebook) %}
<div class="flex-row">
<span>
{{ file.relative_name }} ({{ (file.size / 1024) | number_format(2) | default(-1) }}kb)
Expand Down
16 changes: 13 additions & 3 deletions site/app/views/calendar/CalendarView.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@
use app\models\User;
use app\views\AbstractView;
use app\views\NavigationView;
use app\models\Course;

class CalendarView extends AbstractView {
/**
* This function shows a calendar with arbitrary items. It first shows a calendar view that list all items on
* calendar by their given date. Then it shows a series of tables to list all items.
*
* @param CalendarInfo $info the information used to fill the calendar
* @param array<Course> $courses the courses that will be shown
* @return string
* @see NavigationView::gradeableSections
*/
public function showCalendar(CalendarInfo $info, bool $in_course = false): string {
public function showCalendar(CalendarInfo $info, array $courses, bool $in_course = false): string {

$year = (isset($_GET['year']) && $_GET['year'] != "") ? (int) $_GET['year'] : (int) date("Y");
$month = (isset($_GET['month']) && $_GET['month'] != "") ? (int) $_GET['month'] : (int) date("n");
Expand All @@ -35,6 +37,13 @@ public function showCalendar(CalendarInfo $info, bool $in_course = false): strin
$year = (int) date("Y");
}

//Create list of courses and their term
$formatted_courses = [];
foreach ($courses as $course) {
$course_string = sprintf("%s %s", $course->getTitle(), $course->getTerm());
array_push($formatted_courses, $course_string);
}

$this->core->getOutput()->addInternalCss("navigation.css");
$this->core->getOutput()->addInternalCss('calendar.css');
$this->core->getOutput()->addInternalJs('calendar.js');
Expand All @@ -53,14 +62,15 @@ public function showCalendar(CalendarInfo $info, bool $in_course = false): strin
"curr_month" => date("n"), // the current month
"curr_day" => date("d"), // the current date
'date_format' => $this->core->getConfig()->getDateTimeFormat()->getFormat('gradeable'),
"gradeables_by_date" => $info->getItemsByDate(),
"gradeables_by_date" => $info->getItemsByDateInCourses(),
"gradeables_by_section" => $info->getItemsBySections(),
"empty_message" => $info->getEmptyMessage(),
"in_course" => $in_course,
"is_instructor" => $this->core->getUser()->getGroup() === User::GROUP_INSTRUCTOR,
"colors" => $info->getColors(),
"instructor_courses" => $this->core->getQueries()->getInstructorLevelUnarchivedCourses($this->core->getUser()->getId()),
"view_cookie" => isset($_COOKIE['view']) ? $_COOKIE['view'] : "month"
"view_cookie" => isset($_COOKIE['view']) ? $_COOKIE['view'] : "month",
"course_names" => $formatted_courses
]);
}
}
23 changes: 1 addition & 22 deletions site/app/views/submission/HomeworkView.php
Original file line number Diff line number Diff line change
Expand Up @@ -1034,29 +1034,8 @@ private function renderVersionBox(GradedGradeable $graded_gradeable, $version_in

$files = $version_instance->getFiles();

$notebook_data = null;
$hidefiles = [];
if ($autograding_config->isNotebookGradeable()) {
$notebook_model = $autograding_config->getUserSpecificNotebook($this->core->getUser()->getId());

$notebook = $notebook_model->getNotebook();
if ($graded_gradeable !== null) {
$notebook_data = $notebook_model->getMostRecentNotebookSubmissions(
$graded_gradeable->getAutoGradedGradeable()->getHighestVersion(),
$notebook,
$this->core->getUser()->getId(),
$version_instance->getVersion(),
$graded_gradeable->getGradeableId()
);
}
foreach ($notebook_data as $note) {
if (array_key_exists('filename', $note)) {
array_push($hidefiles, $note['filename']);
}
}
}
$param = array_merge($param, [
'notebook' => $hidefiles,
'is_notebook' => $autograding_config->isNotebookGradeable(),
'submission_time' => DateUtils::dateTimeToString($version_instance->getSubmissionTime()),
'days_late' => $version_instance->getDaysLate(),
'num_autogrades' => $version_instance->getHistoryCount(),
Expand Down
5 changes: 0 additions & 5 deletions site/phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7676,11 +7676,6 @@ parameters:
count: 1
path: app/models/CalendarInfo.php

-
message: "#^Method app\\\\models\\\\CalendarInfo\\:\\:getItemsByDate\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: app/models/CalendarInfo.php

-
message: "#^Method app\\\\models\\\\CalendarInfo\\:\\:getItemsBySections\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
Expand Down

0 comments on commit edc452f

Please sign in to comment.