Skip to content

Commit

Permalink
Merge pull request #28 from xyng/stationen
Browse files Browse the repository at this point in the history
Stationen
  • Loading branch information
xyng authored Apr 6, 2021
2 parents ccabb79 + 1e267d6 commit f5b70b9
Show file tree
Hide file tree
Showing 38 changed files with 1,381 additions and 146 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -257,3 +257,5 @@ dist
yuoshi.zip

.webpack.env

.vscode
3 changes: 2 additions & 1 deletion .webpack.env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# copy this file to .webpack.env and change settings there
# copy this file to .webpack.env and change settings there.
STUDIP_URL=http://localhost:8123
PLUGIN_PATH=/plugins_packages/xyng/Yuoshi
API_PATH=/jsonapi.php/v1

41 changes: 28 additions & 13 deletions Yuoshi.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
use Xyng\Yuoshi\Api\Controller\TaskContentSolutionsController;
use Xyng\Yuoshi\Api\Controller\TasksController;
use Xyng\Yuoshi\Api\Controller\TaskSolutionsController;
use Xyng\Yuoshi\Api\Controller\StationController;

class Yuoshi extends StudIPPlugin implements StandardPlugin, SystemPlugin, JsonApiPlugin {
public function __construct() {
class Yuoshi extends StudIPPlugin implements StandardPlugin, SystemPlugin, JsonApiPlugin
{
public function __construct()
{
parent::__construct();

// Enable this when changing tables.
Expand All @@ -36,7 +39,7 @@ public function __construct() {
*
* @return object template object to render or NULL
*/
function getInfoTemplate($course_id)
public function getInfoTemplate($course_id)
{
// TODO: Implement getInfoTemplate() method.
}
Expand All @@ -57,7 +60,7 @@ function getInfoTemplate($course_id)
*
* @return object navigation item to render or NULL
*/
function getIconNavigation($course_id, $last_visit, $user_id)
public function getIconNavigation($course_id, $last_visit, $user_id)
{
// TODO: Implement getIconNavigation() method.
}
Expand All @@ -76,7 +79,7 @@ function getIconNavigation($course_id, $last_visit, $user_id)
*
* @return array navigation item to render or NULL
*/
function getTabNavigation($course_id)
public function getTabNavigation($course_id)
{
return [
'yuoshi' => new Navigation(_('yUOShi'), PluginEngine::getURL($this, array(), 'index'))
Expand All @@ -89,17 +92,26 @@ function getTabNavigation($course_id)
public function registerAuthenticatedRoutes(\Slim\App $app)
{
$app->get('/courses/{id}/packages', PackagesController::class . ':index');
$app->post('/courses/{id}/packages', PackagesController::class . ':create');

$app->get('/packages', PackagesController::class . ':index');
$app->post('/packages', PackagesController::class . ':create');
$app->get('/packages/{id}', PackagesController::class . ':show');
$app->get('/packages/export/{package_id}', PackageImportController::class . ':export');
$app->get('/packages/{id}/tasks', TasksController::class . ':index');
$app->get('/packages/{id}/nextTask', TasksController::class . ':nextTask');
$app->get('/packages/{id}/stations', StationController::class . ':index');
$app->post('/packages', PackagesController::class . ':create');
$app->post('/packages/import/{course_id}', PackageImportController::class . ':import');
$app->get('/packages/{id}', PackagesController::class . ':show');
$app->post('/courses/{id}/packages', PackagesController::class . ':create');
$app->patch('/packages/{id}', PackagesController::class . ':update');
$app->delete('/packages/{package_id}', PackagesController::class . ':delete');
$app->get('/packages/{id}/tasks', TasksController::class . ':index');
$app->get('/packages/{id}/nextTask', TasksController::class . ':nextTask');

$app->get('/stations', StationController::class . ':index');
$app->get('/stations/{id}', StationController::class . ':show');
$app->get('/stations/{id}/tasks', StationController::class . ':show');

$app->delete('/stations/{station_id}', StationController::class . ':delete');
$app->post('/stations', StationController::class . ':create');
$app->get('/stations/{id}/nextTask', TasksController::class . ':nextTask');

$app->get('/tasks', TasksController::class . ':index');
$app->post('/tasks', TasksController::class . ':create');
Expand All @@ -111,7 +123,6 @@ public function registerAuthenticatedRoutes(\Slim\App $app)
$app->patch('/tasks/{task_id}/contents/{content_id}', TaskContentsController::class . ':update');
$app->get('/tasks/{task_id}/task_solutions', TaskSolutionsController::class . ':index');
$app->get('/tasks/{task_id}/current_task_solution', TaskSolutionsController::class . ':getCurrentSolution');

$app->get('/task_solutions', TaskSolutionsController::class . ':index');
$app->get('/task_solutions/{task_solution_id}', TaskSolutionsController::class . ':show');
$app->patch('/task_solutions/{task_solution_id}', TaskSolutionsController::class . ':update');
Expand Down Expand Up @@ -166,7 +177,9 @@ public function registerSchemas(): array
{
return [
\Xyng\Yuoshi\Model\UserPackageProgress::class => \Xyng\Yuoshi\Api\Schema\UserPackageProgress::class,
\Xyng\Yuoshi\Model\UserStationProgress::class => \Xyng\Yuoshi\Api\Schema\UserStationProgress::class,
\Xyng\Yuoshi\Model\Packages::class => \Xyng\Yuoshi\Api\Schema\Packages::class,
\Xyng\Yuoshi\Model\Stations::class => \Xyng\Yuoshi\Api\Schema\Stations::class,
\Xyng\Yuoshi\Model\Tasks::class => \Xyng\Yuoshi\Api\Schema\Tasks::class,
\Xyng\Yuoshi\Model\TaskContents::class => \Xyng\Yuoshi\Api\Schema\Contents::class,
\Xyng\Yuoshi\Model\TaskContentQuests::class => \Xyng\Yuoshi\Api\Schema\Quests::class,
Expand All @@ -193,12 +206,14 @@ public function perform($unconsumedPath)
$dispatcher->dispatch($unconsumedPath);
}

public static function onEnable($pluginId) {
public static function onEnable($pluginId)
{
// enable nobody role by default
\RolePersistence::assignPluginRoles($pluginId, array(7));
}

private function loadAssets($keys = []) {
private function loadAssets($keys = [])
{
// get webpack manifest
$path = __DIR__ . DIRECTORY_SEPARATOR . 'dist' . DIRECTORY_SEPARATOR . 'manifest.json';
$json = file_get_contents($path);
Expand Down
Empty file added app/contexts/CU
Empty file.
61 changes: 61 additions & 0 deletions app/contexts/CurrentStationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { createContext, useContext } from "react"

import useGetModelFromListOrFetch from "../helpers/useGetModelFromListOrFetch"
import Station from "../models/Station"

import { useStationContext } from "./StationContext"

interface CurrentStationContextInterface {
station: Station
updateStation: (station: Station, reload?: boolean) => Promise<void>
}
const CurrentStationContext = createContext<CurrentStationContextInterface | null>(
null
)

export const useCurrentStationContext = () => {
const ctx = useContext(CurrentStationContext)

if (ctx === null) {
throw new Error("No CurrentStationContext available.")
}

return ctx
}

const fetchStation = async (stationId: string) => {
const station = (
await Station.with("station").find(stationId)
).getData() as Station | null

if (!station) {
throw new Error("Station not found")
}

return station
}

export const CurrentStationContextProvider: React.FC<{
stationId?: string
}> = ({ children, stationId }) => {
const { station, updateStation, reloadStations } = useStationContext()
const { entityData, updateEntity } = useGetModelFromListOrFetch(
stationId,
station,
stationId ? [stationId, "stationId"] : null,
fetchStation,
updateStation,
reloadStations
)

const ctx = {
station: entityData,
updateStation: updateEntity,
}

return (
<CurrentStationContext.Provider value={ctx}>
{children}
</CurrentStationContext.Provider>
)
}
83 changes: 83 additions & 0 deletions app/contexts/StationContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { createContext, useCallback, useContext, useMemo } from "react"
import { PluralResponse } from "coloquent"
import useSWR, { responseInterface } from "swr"

import Station from "../models/Station"
import updateModelList from "../helpers/updateModelList"

import { useCurrentPackageContext } from "./CurrentPackageContext"
interface StationContextInterface {
station: Station[]
updateStation: (updated: Station, reload?: boolean) => Promise<void>
reloadStations: () => Promise<boolean>
mutate: responseInterface<Station[], any>["mutate"]
}
const StationContext = createContext<StationContextInterface | null>(null)

export const useStationContext = () => {
const ctx = useContext(StationContext)

if (ctx === null) {
throw new Error("No StationContextProvider available.")
}

return ctx
}

const fetchStationsForPackage = (byUser: boolean) => async (
packageId: string
): Promise<Station[]> => {
let query = Station.where("package", packageId)

if (byUser) {
query = query.with("stationUserProgress.user")
} else {
query = query.with("stationTotalProgress")
}

const stationItem = (await query.get()) as PluralResponse

return stationItem.getData() as Station[]
}

export const StationContextProvider: React.FC<{
byUser?: boolean
}> = ({ children, byUser }) => {
const { currentPackage } = useCurrentPackageContext()
const cacheKey = useMemo(
() => (byUser ? "package/stations_by_user" : "package/stations"),
[byUser]
)
const fetch = useMemo(() => fetchStationsForPackage(!!byUser), [byUser])

const { data, mutate, revalidate } = useSWR(
() =>
currentPackage.getApiId()
? [currentPackage.getApiId(), cacheKey]
: null,
fetch,
{ suspense: true }
)

const updateStation = useCallback(
async (updatedStation: Station, reload: boolean = false) => {
await mutate(updateModelList(updatedStation), reload)
},
[mutate]
)

const ctx = {
station: (data as Station[]).sort((a, b) => {
return a.getSort() - b.getSort()
}),
updateStation,
reloadStations: revalidate,
mutate,
}

return (
<StationContext.Provider value={ctx}>
{children}
</StationContext.Provider>
)
}
18 changes: 9 additions & 9 deletions app/contexts/TasksContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import useSWR, { responseInterface } from "swr"
import Task from "../models/Task"
import updateModelList from "../helpers/updateModelList"

import { useCurrentPackageContext } from "./CurrentPackageContext"
import { useCurrentStationContext } from "./CurrentStationContext"

interface TasksContextInterface {
tasks: Task[]
Expand All @@ -25,20 +25,20 @@ export const useTasksContext = () => {
return ctx
}

const fetchTasksForPackage = async (packageId: string): Promise<Task[]> => {
const packageItem = (await Task.where(
"package",
packageId
const fetchTasksForStations = async (stationId: string): Promise<Task[]> => {
const stationItem = (await Task.where(
"station",
stationId
).get()) as PluralResponse

return packageItem.getData() as Task[]
return stationItem.getData() as Task[]
}

export const TasksContextProvider: React.FC = ({ children }) => {
const { currentPackage } = useCurrentPackageContext()
const { station } = useCurrentStationContext()
const { data, mutate, revalidate } = useSWR(
() => [currentPackage.getApiId(), "package/tasks"],
fetchTasksForPackage,
() => [station.getApiId(), "station/tasks"],
fetchTasksForStations,
{ suspense: true }
)

Expand Down
9 changes: 9 additions & 0 deletions app/models/Package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ToOneRelation } from "coloquent/dist/relation/ToOneRelation"

import { AppModelWithDate } from "./AppModel"
import Course from "./Course"
import Station from "./Station"
import Task from "./Task"
import PackageProgress from "./PackageProgress"

Expand Down Expand Up @@ -47,6 +48,10 @@ export default class Package extends AppModelWithDate<Attributes> {
return this.setRelation("course", course)
}

setStation(station: Station) {
return this.setRelation("stations", station)
}

tasks(): ToManyRelation {
return this.hasMany(Task, "tasks")
}
Expand All @@ -55,6 +60,10 @@ export default class Package extends AppModelWithDate<Attributes> {
return this.getRelation("tasks")
}

getStations(): Station[] {
return this.getRelation("stations")
}

packageTotalProgress(): ToOneRelation {
return this.hasOne(PackageProgress, "packageTotalProgress")
}
Expand Down
Loading

0 comments on commit f5b70b9

Please sign in to comment.