From 41b3733ff6b1dd9213c1fd610b1e2606f1294933 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Willms <tleilax+studip@gmail.com> Date: Wed, 6 Mar 2024 13:15:21 +0000 Subject: [PATCH] fixes #3750 Closes #3750 Merge request studip/studip!2607 --- app/routes/Events.php | 26 ++--- .../Fix/EndTimeWeeklyRecurredEvents.php | 40 ------- cli/studip | 1 - lib/classes/JsonApi/SchemaMap.php | 2 +- ...arEvent.php => CalendarDateAssignment.php} | 2 +- lib/classes/Privacy.php | 106 +++++++++--------- lib/classes/UserManagement.class.php | 20 +++- lib/extern/ExternPagePersonDetails.php | 56 ++++----- lib/models/User.class.php | 2 +- 9 files changed, 118 insertions(+), 137 deletions(-) delete mode 100644 cli/Commands/Fix/EndTimeWeeklyRecurredEvents.php rename lib/classes/JsonApi/Schemas/{CalendarEvent.php => CalendarDateAssignment.php} (96%) diff --git a/app/routes/Events.php b/app/routes/Events.php index c07c6e69ca5..3612d9a5a37 100644 --- a/app/routes/Events.php +++ b/app/routes/Events.php @@ -40,31 +40,31 @@ class Events extends \RESTAPI\RouteMap $this->error(401); } - $start = time(); - $end = strtotime('+2 weeks', $start); - $list = SingleCalendar::getEventList($user_id, $start, $end, null, [], [ - 'CourseEvent', - 'CourseCancelledEvent', - 'CourseMarkedEvent', - ]); + $start = new \DateTime(); + $end = clone $start; + $end = $end->add(new \DateInterval('P2W')); + + $list = array_merge( + \CalendarCourseDate::getEvents($start, $end, $user_id), + \CalendarCourseExDate::getEvents($start, $end, $user_id) + ); $json = []; $events = array_slice($list, $this->offset, $this->limit); ; foreach ($events as $event) { - $singledate = new SingleDate($event->id); - $course_uri = $this->urlf('/course/%s', [htmlReady($event->getSeminarId())]); + $course_uri = $this->urlf('/course/%s', [htmlReady($event->course_id)]); $json[] = [ 'event_id' => $event->id, 'course' => $course_uri, - 'start' => $event->getStart(), - 'end' => $event->getEnd(), + 'start' => $event->date, + 'end' => $event->end_time, 'title' => $event->getTitle(), 'description' => $event->getDescription() ?: '', 'categories' => $event->toStringCategories() ?: '', - 'room' => html_entity_decode(strip_tags($singledate->getRoom() ?: $singledate->getFreeRoomText() ?: '')), - 'canceled' => $singledate->isHoliday() ?: false, + 'room' => $event->getRoomName(), + 'canceled' => $event instanceof \CourseExDate || holiday($event->date), ]; } diff --git a/cli/Commands/Fix/EndTimeWeeklyRecurredEvents.php b/cli/Commands/Fix/EndTimeWeeklyRecurredEvents.php deleted file mode 100644 index 40e7a2b0e02..00000000000 --- a/cli/Commands/Fix/EndTimeWeeklyRecurredEvents.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php - -namespace Studip\Cli\Commands\Fix; - -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; - -class EndTimeWeeklyRecurredEvents extends Command -{ - protected static $defaultName = 'fix:end-time-weekly-recurred-events'; - - protected function configure(): void - { - $this->setDescription('Fix end time weekly recurred events'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $io = new SymfonyStyle($input, $output); - $events = \EventData::findBySQL("rtype = 'WEEKLY' AND IFNULL(count, 0) > 0"); - $cal_event = new \CalendarEvent(); - - $i = 0; - - foreach ($events as $event) { - $id = $event->getId(); - $cal_event->event = $event; - $rrule = $cal_event->getRecurrence(); - $cal_event->setRecurrence($rrule); - $event->expire = $cal_event->event->expire; - $event->setId($id); - $event->store(); - $i++; - } - $io->info('Wrong end time of recurrence fixed for ' . $i . ' events.'); - return Command::SUCCESS; - } -} diff --git a/cli/studip b/cli/studip index 9da3b945877..d981bd96884 100755 --- a/cli/studip +++ b/cli/studip @@ -36,7 +36,6 @@ $commands = [ Commands\Fix\Biest7789::class, Commands\Fix\Biest7866::class, Commands\Fix\Biest8136::class, - Commands\Fix\EndTimeWeeklyRecurredEvents::class, Commands\Fix\IconDimensions::class, Commands\HelpContent\Migrate::class, Commands\Migrate\MigrateList::class, diff --git a/lib/classes/JsonApi/SchemaMap.php b/lib/classes/JsonApi/SchemaMap.php index a0d21a3af04..97212bc6552 100644 --- a/lib/classes/JsonApi/SchemaMap.php +++ b/lib/classes/JsonApi/SchemaMap.php @@ -18,7 +18,7 @@ class SchemaMap \BlubberStatusgruppeThread::class => Schemas\BlubberStatusgruppeThread::class, \BlubberThread::class => Schemas\BlubberThread::class, - \CalendarDateAssignment::class => Schemas\CalendarEvent::class, + \CalendarDateAssignment::class => Schemas\CalendarDateAssignment::class, \ConsultationBlock::class => Schemas\ConsultationBlock::class, \ConsultationBooking::class => Schemas\ConsultationBooking::class, \ConsultationSlot::class => Schemas\ConsultationSlot::class, diff --git a/lib/classes/JsonApi/Schemas/CalendarEvent.php b/lib/classes/JsonApi/Schemas/CalendarDateAssignment.php similarity index 96% rename from lib/classes/JsonApi/Schemas/CalendarEvent.php rename to lib/classes/JsonApi/Schemas/CalendarDateAssignment.php index fc5a1d81a47..3aec6eadb0a 100644 --- a/lib/classes/JsonApi/Schemas/CalendarEvent.php +++ b/lib/classes/JsonApi/Schemas/CalendarDateAssignment.php @@ -5,7 +5,7 @@ namespace JsonApi\Schemas; use Neomerx\JsonApi\Contracts\Schema\ContextInterface; use Neomerx\JsonApi\Schema\Link; -class CalendarEvent extends SchemaProvider +class CalendarDateAssignment extends SchemaProvider { const TYPE = 'calendar-events'; const REL_OWNER = 'owner'; diff --git a/lib/classes/Privacy.php b/lib/classes/Privacy.php index 670f3023409..38e6e80c4af 100644 --- a/lib/classes/Privacy.php +++ b/lib/classes/Privacy.php @@ -18,69 +18,69 @@ class Privacy */ private static $privacy_classes = [ 'core' => [ - 'User', - 'DataField', - 'DatafieldEntryModel', - 'UserConfig', - 'HelpTourUser', - 'Grading\Instance', - 'LogEvent', + User::class, + DataField::class, + DatafieldEntryModel::class, + UserConfig::class, + HelpTourUser::class, + Grading\Instance::class, + LogEvent::class, ], 'date' => [ - 'CalendarEvent', - 'CalendarDate', - 'CourseDate', - 'CourseExDate', + CalendarDateAssignment::class, + CalendarDate::class, + CourseDate::class, + CourseExDate::class, ], 'message' => [ - 'BlubberThread', - 'BlubberComment', - 'StudipNews', - 'StudipComment', - 'Message', - 'MessageUser', + BlubberThread::class, + BlubberComment::class, + StudipNews::class, + StudipComment::class, + Message::class, + MessageUser::class, ], 'content' => [ - 'FileRef', - 'ForumEntry', - 'WikiPage', - 'Courseware\Unit', - 'Courseware\StructuralElement', - 'Courseware\StructuralElementComment', - 'Courseware\StructuralElementFeedback', - 'Courseware\TaskGroup', - 'Courseware\TaskFeedback', - 'Courseware\Bookmark', - 'Courseware\Container', - 'Courseware\Block', - 'Courseware\BlockComment', - 'Courseware\BlockFeedback', - 'Courseware\UserDataField', - 'Courseware\UserProgress' + FileRef::class, + ForumEntry::class, + WikiPage::class, + Courseware\Unit::class, + Courseware\StructuralElement::class, + Courseware\StructuralElementComment::class, + Courseware\StructuralElementFeedback::class, + Courseware\TaskGroup::class, + Courseware\TaskFeedback::class, + Courseware\Bookmark::class, + Courseware\Container::class, + Courseware\Block::class, + Courseware\BlockComment::class, + Courseware\BlockFeedback::class, + Courseware\UserDataField::class, + Courseware\UserProgress::class, ], 'quest' => [ - 'Evaluation', - 'Questionnaire', - 'QuestionnaireAnswer', - 'QuestionnaireAnonymousAnswer', - 'QuestionnaireAssignment', - 'eTask\Attempt', - 'eTask\Response', - 'eTask\Task', - 'eTask\Test', + Evaluation::class, + Questionnaire::class, + QuestionnaireAnswer::class, + QuestionnaireAnonymousAnswer::class, + QuestionnaireAssignment::class, + eTask\Attempt::class, + eTask\Response::class, + eTask\Task::class, + eTask\Test::class, ], 'membership' => [ - 'Course', - 'CourseMember', - 'AdmissionApplication', - 'ArchivedCourse', - 'ArchivedCourseMember', - 'Statusgruppen', - 'StatusgruppeUser', - 'InstituteMember', - 'UserStudyCourse', - 'Fach', - 'Abschluss', + Course::class, + CourseMember::class, + AdmissionApplication::class, + ArchivedCourse::class, + ArchivedCourseMember::class, + Statusgruppen::class, + StatusgruppeUser::class, + InstituteMember::class, + UserStudyCourse::class, + Fach::class, + Abschluss::class, ], 'plugins' => [ ], diff --git a/lib/classes/UserManagement.class.php b/lib/classes/UserManagement.class.php index 3efae350047..c831b855a4a 100644 --- a/lib/classes/UserManagement.class.php +++ b/lib/classes/UserManagement.class.php @@ -1161,7 +1161,25 @@ class UserManagement // delete all private appointments of this user if (Config::get()->CALENDAR_ENABLE) { - $count = CalendarEvent::deleteBySQL('range_id = ?', [$user_id]); + // delete private appointments (omit group appointments) + $count = CalendarDate::deleteBySQL( + '`id` IN ( + SELECT `id` + FROM ( + SELECT `id`, COUNT(*) + FROM `calendar_dates` + JOIN `calendar_date_assignments` + ON `calendar_dates`.`id` = `calendar_date_assignments`.`calendar_date_id` + WHERE `calendar_dates`.`author_id` = :user_id + GROUP BY `id` + HAVING COUNT(*) = 1 + ORDER BY NULL + ) AS `cal_date_delete` + )', + [':user_id' => $user_id] + ); + // delete assignments to group appointments + $count += CalendarDateAssignment::deleteBySQL('`range_id` = ?', [$user_id]); if ($count) { $msg .= 'info§' . sprintf(_('%s Einträge aus den Terminen gelöscht.'), $count) . '§'; } diff --git a/lib/extern/ExternPagePersonDetails.php b/lib/extern/ExternPagePersonDetails.php index a71124e0c55..49c754c16a1 100644 --- a/lib/extern/ExternPagePersonDetails.php +++ b/lib/extern/ExternPagePersonDetails.php @@ -360,44 +360,48 @@ class ExternPagePersonDetails extends ExternPage return []; } - $list_start = new DateTimeImmutable(); - $list_end = $list_start->modify('+ 7 days'); - $events = SingleCalendar::getEventList( + $list_start = new DateTime(); + $list_end = clone $list_start; + $list_end = $list_end->add(new DateInterval('P7D')); + + $assigned_events = CalendarDateAssignment::getEvents( + $list_start, + $list_end, $user->id, - $list_start->getTimestamp(), - $list_end->getTimestamp(), - null, - ['class' => 'PUBLIC'], - ['CalendarEvent'] + ['PUBLIC'] ); $content['APPOINTMENTS_START'] = $list_start->getTimestamp(); $content['APPOINTMENTS_END'] = $list_end->getTimestamp(); $content_events = []; - if (!empty($events)) { - foreach ($events as $event) { - if ($event->isDayEvent()) { - $date = date('d.m.Y', $event->getStart()) . ' (' . _('ganztägig') . ')'; + if (!empty($assigned_events)) { + foreach ($assigned_events as $assigned_event) { + $event = $assigned_event->calendar_date; + if (!$event) { + continue; + } + if ($event->isWholeDay()) { + $date = date('d.m.Y', $event->begin) . ' (' . _('ganztägig') . ')'; } else { - $date = date('d.m.Y G:H:s', $event->getStart()); - if (date('dmY', $event->getStart()) === date('dmY', $event->getEnd())) { - $date .= date('d.m.Y G:H:s', $event->getEnd()); + $date = date('d.m.Y G:i:s', $event->begin); + if (date('dmY', $event->begin) === date('dmY', $event->end)) { + $date .= date('d.m.Y G:i:s', $event->end); } else { - $date .= ' - ' . date('d.m.Y G:H:s', $event->getEnd()); + $date .= ' - ' . date('d.m.Y G:i:s', $event->end); } } $content_events[] = [ 'DATE' => $date, - 'TITLE' => $event->getTitle(), - 'DESCRIPTION' => $event->getDescription(), - 'LOCATION' => $event->getLocation(), - 'RECURRENCE' => $event->toStringRecurrence(), - 'CATEGORY' => $event->toStringCategories(), - 'PRIORITY' => $event->toStringPriority(), - 'START' => date('d.m.Y G:H:s', $event->getStart()), - 'END' => date('d.m.Y G:H:s', $event->getEnd()), - 'TIMESTAMP_START' => $event->getStart(), - 'TIMESTAMP_END' => $event->getEnd(), + 'TITLE' => $event->title, + 'DESCRIPTION' => $event->description, + 'LOCATION' => $event->location, + 'RECURRENCE' => $event->getRepetitionAsString(), + 'CATEGORY' => $event->getCategoryAsString(), + 'PRIORITY' => _('Keine Angabe'), + 'START' => date('d.m.Y G:i:s', $event->begin), + 'END' => date('d.m.Y G:i:s', $event->end), + 'TIMESTAMP_START' => $event->begin, + 'TIMESTAMP_END' => $event->end, ]; } } diff --git a/lib/models/User.class.php b/lib/models/User.class.php index 5f1d6a0e3f0..dfd4d18a890 100644 --- a/lib/models/User.class.php +++ b/lib/models/User.class.php @@ -780,7 +780,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject, Studip\Calendar\ // Non-private dates. if (Config::get()->CALENDAR_ENABLE) { - $dates = CalendarEvent::countBySql('range_id = ?', [$this->id]); + $dates = CalendarDateAssignment::countBySql('range_id = ?', [$this->id]); } else { $dates = []; } -- GitLab