diff --git a/assets.go b/assets.go
index 16d8de7..137a155 100644
--- a/assets.go
+++ b/assets.go
@@ -10,7 +10,7 @@ import (
"net/http"
)
-//go:embed ui/build/* ui/build/_app/* ui/build/_app/assets/pages/* ui/build/_app/pages/* ui/build/_app/pages/grades/* ui/build/_app/pages/surveys/* ui/build/_app/pages/surveys/_sid_/* ui/build/_app/pages/surveys/_sid_/responses/* ui/build/_app/pages/users/* ui/build/_app/pages/users/_uid_/* ui/build/_app/pages/users/_uid_/surveys/*
+//go:embed ui/build/* ui/build/_app/* ui/build/_app/assets/pages/* ui/build/_app/pages/* ui/build/_app/pages/grades/* ui/build/_app/pages/surveys/* ui/build/_app/pages/surveys/_sid_/* ui/build/_app/pages/surveys/_sid_/responses/* ui/build/_app/pages/users/* ui/build/_app/pages/users/_uid_/* ui/build/_app/pages/users/_uid_/surveys/* ui/build/_app/pages/works/_wid_/* ui/build/_app/pages/works/*
var _assets embed.FS
var Assets http.FileSystem
diff --git a/static.go b/static.go
index 59b7788..2bae2d2 100644
--- a/static.go
+++ b/static.go
@@ -59,6 +59,8 @@ func init() {
Router().GET("/surveys/*_", serveOrReverse("/"))
Router().GET("/users", serveOrReverse("/"))
Router().GET("/users/*_", serveOrReverse("/"))
+ Router().GET("/works", serveOrReverse("/"))
+ Router().GET("/works/*_", serveOrReverse("/"))
Router().GET("/css/*_", serveOrReverse(""))
Router().GET("/fonts/*_", serveOrReverse(""))
Router().GET("/img/*_", serveOrReverse(""))
diff --git a/ui/src/components/SurveyList.svelte b/ui/src/components/SurveyList.svelte
index 2dae7ab..2e72224 100644
--- a/ui/src/components/SurveyList.svelte
+++ b/ui/src/components/SurveyList.svelte
@@ -7,7 +7,9 @@
import { getSurveys } from '../lib/surveys';
import { getScore } from '../lib/users';
- let req_surveys = getSurveys();
+ export let allworks = false;
+
+ let req_surveys = getSurveys(allworks);
export let direct = null;
req_surveys.then((surveys) => {
@@ -17,6 +19,18 @@
}
}
});
+
+ function gotoSurvey(survey) {
+ if (survey.kind === "w") {
+ goto(`works/${survey.id}`);
+ } else if (survey.direct != null) {
+ goto(`surveys/${survey.id}/live`);
+ } else if ($user.is_admin) {
+ goto(`surveys/${survey.id}/responses`);
+ } else {
+ goto(`surveys/${survey.id}`);
+ }
+ }
@@ -38,7 +52,7 @@
{:then surveys}
- {#each surveys as survey, sid (survey.id)}
+ {#each surveys as survey, sid (survey.kind + survey.id)}
{#if (survey.shown || survey.direct != null || ($user && $user.is_admin)) && (!$user || (!$user.was_admin || $user.promo == survey.promo) || $user.is_admin)}
{#if $user && $user.is_admin && (sid == 0 || surveys[sid-1].promo != survey.promo)}
@@ -47,7 +61,7 @@
{/if}
- goto(survey.direct != null ?`surveys/${survey.id}/live`:$user.is_admin?`surveys/${survey.id}/responses`:`surveys/${survey.id}`)}>
+
gotoSurvey(survey)}>
{#if !survey.shown}{/if}
{survey.title}
@@ -55,12 +69,12 @@
|
{#if survey.startAvailability() > Date.now()}
-
+ |
|
{:else}
-
+ |
|
diff --git a/ui/src/components/WorkAdmin.svelte b/ui/src/components/WorkAdmin.svelte
new file mode 100644
index 0000000..85fe95b
--- /dev/null
+++ b/ui/src/components/WorkAdmin.svelte
@@ -0,0 +1,135 @@
+
+
+
diff --git a/ui/src/lib/surveys.js b/ui/src/lib/surveys.js
index 27b5edd..b3904d3 100644
--- a/ui/src/lib/surveys.js
+++ b/ui/src/lib/surveys.js
@@ -1,8 +1,10 @@
import { getQuestions } from './questions';
import { Response } from './response';
+import { Work } from './works';
export class Survey {
constructor(res) {
+ this.kind = "s";
if (res) {
this.update(res);
}
@@ -126,10 +128,19 @@ export class Survey {
}
}
-export async function getSurveys() {
- const res = await fetch(`api/surveys`, {headers: {'Accept': 'application/json'}})
+export async function getSurveys(allworks) {
+ const res = await fetch(allworks?`api/all_works`:`api/surveys`, {headers: {'Accept': 'application/json'}})
if (res.status == 200) {
- return (await res.json()).map((s) => new Survey(s));
+ if (allworks) {
+ return (await res.json()).map((s) => {
+ if (s.kind == "survey")
+ return new Survey(s);
+ else
+ return new Work(s);
+ });
+ } else {
+ return (await res.json()).map((s) => new Survey(s));
+ }
} else {
throw new Error((await res.json()).errmsg);
}
diff --git a/ui/src/lib/works.js b/ui/src/lib/works.js
new file mode 100644
index 0000000..57fd02e
--- /dev/null
+++ b/ui/src/lib/works.js
@@ -0,0 +1,108 @@
+export class Work {
+ constructor(res) {
+ this.kind = "w";
+ if (res) {
+ this.update(res);
+ }
+ }
+
+ update({ id, title, promo, group, shown, submission_url, corrected, start_availability, end_availability }) {
+ this.id = id;
+ this.title = title;
+ this.promo = promo;
+ this.group = group;
+ this.shown = shown;
+ this.submission_url = submission_url;
+ this.corrected = corrected;
+ if (this.start_availability != start_availability) {
+ this.start_availability = start_availability;
+ delete this.__start_availability;
+ }
+ if (this.end_availability != end_availability) {
+ this.end_availability = end_availability;
+ delete this.__end_availability;
+ }
+ }
+
+ startAvailability() {
+ if (!this.__start_availability) {
+ this.__start_availability = new Date(this.start_availability)
+ }
+ return this.__start_availability
+ }
+
+ endAvailability() {
+ if (!this.__end_availability) {
+ this.__end_availability = new Date(this.end_availability)
+ }
+ return this.__end_availability
+ }
+
+ isFinished() {
+ return this.endAvailability() < new Date();
+ }
+
+ async save() {
+ const res = await fetch(this.id?`api/works/${this.id}`:'api/works', {
+ method: this.id?'PUT':'POST',
+ headers: {'Accept': 'application/json'},
+ body: JSON.stringify(this),
+ });
+ if (res.status == 200) {
+ const data = await res.json()
+ this.update(data);
+ return data;
+ } else {
+ throw new Error((await res.json()).errmsg);
+ }
+ }
+
+ async duplicate() {
+ if (this.id) {
+ const oldSurveyId = this.id;
+ delete this.id;
+ const res = await fetch(`api/works`, {
+ method: 'POST',
+ headers: {'Accept': 'application/json'},
+ body: JSON.stringify(this),
+ });
+ if (res.status == 200) {
+ return await res.json();
+ } else {
+ throw new Error((await res.json()).errmsg);
+ }
+ }
+ }
+
+ async delete() {
+ if (this.id) {
+ const res = await fetch(`api/works/${this.id}`, {
+ method: 'DELETE',
+ headers: {'Accept': 'application/json'},
+ });
+ if (res.status == 200) {
+ return true;
+ } else {
+ throw new Error((await res.json()).errmsg);
+ }
+ }
+ }
+}
+
+export async function getWorks() {
+ const res = await fetch(`api/works`, {headers: {'Accept': 'application/json'}})
+ if (res.status == 200) {
+ return (await res.json()).map((s) => new Work(s));
+ } else {
+ throw new Error((await res.json()).errmsg);
+ }
+}
+
+export async function getWork(wid) {
+ const res = await fetch(`api/works/${wid}`, {headers: {'Accept': 'application/json'}})
+ if (res.status == 200) {
+ return new Work(await res.json());
+ } else {
+ throw new Error((await res.json()).errmsg);
+ }
+}
diff --git a/ui/src/routes/__layout.svelte b/ui/src/routes/__layout.svelte
index a99d9f2..6fd5f94 100644
--- a/ui/src/routes/__layout.svelte
+++ b/ui/src/routes/__layout.svelte
@@ -89,6 +89,7 @@
{#if $user && $user.is_admin}
+ Travaux
Étudiants
{/if}
VIRLI
diff --git a/ui/src/routes/index.svelte b/ui/src/routes/index.svelte
index 852e3f7..96ba01f 100644
--- a/ui/src/routes/index.svelte
+++ b/ui/src/routes/index.svelte
@@ -67,7 +67,7 @@
Vous devez vous identifier pour accéder au contenu.
{/if}
-
+
diff --git a/ui/src/routes/works/[wid]/__layout.svelte b/ui/src/routes/works/[wid]/__layout.svelte
new file mode 100644
index 0000000..6c5b2dc
--- /dev/null
+++ b/ui/src/routes/works/[wid]/__layout.svelte
@@ -0,0 +1,39 @@
+
+
+
+
+{#await work}
+
+
+
Chargement du rendu …
+
+{:then}
+
+{:catch error}
+
+
+ <
+ Travail introuvable
+
+
{error}
+
+{/await}
diff --git a/ui/src/routes/works/[wid]/index.svelte b/ui/src/routes/works/[wid]/index.svelte
new file mode 100644
index 0000000..b640946
--- /dev/null
+++ b/ui/src/routes/works/[wid]/index.svelte
@@ -0,0 +1,34 @@
+
+
+
+
+{#await work then w}
+
+
+ {#if $user && $user.is_admin}
+ edit = false} />
+ {/if}
+{/await}
diff --git a/ui/src/routes/works/index.svelte b/ui/src/routes/works/index.svelte
new file mode 100644
index 0000000..fa4b01d
--- /dev/null
+++ b/ui/src/routes/works/index.svelte
@@ -0,0 +1,99 @@
+
+
+{#if $user && $user.is_admin}
+
+
+
+ {#await getPromos() then promos}
+
+
+
+ {/await}
+{/if}
+
+ Travaux
+
+
+{#await getWorks()}
+
+
+
Chargement des travaux …
+
+{:then works}
+
+
+
+ Intitulé |
+ Date |
+ {#if $user}
+ Score |
+ {/if}
+
+
+
+ {#each works as work, wid (work.id)}
+ {#if (work.shown || ($user && $user.is_admin)) && (!$user || (!$user.was_admin || $user.promo == work.promo) || $user.is_admin)}
+ {#if $user && $user.is_admin && (wid == 0 || works[wid-1].promo != work.promo)}
+
+
+ {work.promo}
+ |
+
+ {/if}
+ goto(`works/${work.id}`)}>
+
+ {#if !work.shown}{/if}
+ {work.title}
+ {#if work.group}{work.group}{/if}
+
+ |
+ {#if work.startAvailability() > Date.now()}
+
+
+
+ |
+ {:else}
+
+
+
+ |
+ {/if}
+ {#if $user}
+ {#if !work.corrected}
+ N/A |
+ {:else}
+
+ {#await getScore(work)}
+
+ {:then score}
+ {score.score}
+ {/await}
+ |
+ {/if}
+ {/if}
+
+ {/if}
+ {/each}
+
+
+{:catch error}
+
+ {error.message}
+
+{/await}
diff --git a/ui/src/routes/works/new.svelte b/ui/src/routes/works/new.svelte
new file mode 100644
index 0000000..efbcfd0
--- /dev/null
+++ b/ui/src/routes/works/new.svelte
@@ -0,0 +1,22 @@
+
+
+
+
+ <
+ Nouveau travail
+
+
+
+
+{#if $user && $user.is_admin}
+ { goto(`works/${e.detail.id}`)}} />
+{/if}