diff --git a/classquiz/db/models.py b/classquiz/db/models.py
index 3105930..dffe88f 100644
--- a/classquiz/db/models.py
+++ b/classquiz/db/models.py
@@ -360,13 +360,15 @@ class OnlyId(BaseModel):
class PublicQuizTivityShare(BaseModel):
id: uuid.UUID
name: str | None
- expire_in: int
+ expire_in: int | None
quiztivity: OnlyId
user: OnlyId
@classmethod
def from_db_model(cls, data: QuizTivityShare):
- expire_in = int((data.expire_at - datetime.now()).seconds / 60)
+ expire_in = None
+ if data.expire_at is not None:
+ expire_in = int((data.expire_at - datetime.now()).seconds / 60)
return cls(
id=data.id,
name=data.name,
diff --git a/classquiz/routers/quiztivity/__init__.py b/classquiz/routers/quiztivity/__init__.py
index 5f3717b..c10458a 100644
--- a/classquiz/routers/quiztivity/__init__.py
+++ b/classquiz/routers/quiztivity/__init__.py
@@ -56,7 +56,9 @@ async def get_all_quiztivities(user: User = Depends(get_current_user)) -> list[Q
@router.get("/{uuid}/shares")
async def get_shares(uuid: UUID, user: User = Depends(get_current_user)) -> list[PublicQuizTivityShare]:
- shares = await QuizTivityShare.objects.filter(quiztivity=uuid, user=user).all()
+ shares = (
+ await QuizTivityShare.objects.filter(quiztivity=uuid, user=user).order_by(QuizTivityShare.expire_at.asc()).all()
+ )
resp_shares = []
for share in shares:
resp_shares.append(PublicQuizTivityShare.from_db_model(share))
diff --git a/classquiz/routers/quiztivity/shares.py b/classquiz/routers/quiztivity/shares.py
index 54848ad..43b92ad 100644
--- a/classquiz/routers/quiztivity/shares.py
+++ b/classquiz/routers/quiztivity/shares.py
@@ -77,4 +77,6 @@ async def get_share(uuid: UUID) -> QuizTivity:
share = await QuizTivityShare.objects.select_related("quiztivity").get_or_none(id=uuid)
if share is None:
raise HTTPException(status_code=404, detail="Share not found")
+ if share.expire_at < datetime.now():
+ raise HTTPException(status_code=410, detail="Already expired")
return share.quiztivity
diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json
index 14b0cbf..414e577 100644
--- a/frontend/src/lib/i18n/locales/en.json
+++ b/frontend/src/lib/i18n/locales/en.json
@@ -357,7 +357,13 @@
"move_right": "Move right",
"title_placeholder": "Enter title here",
"add_new": "Add new",
- "delete": "Delete"
+ "delete": "Delete",
+ "open_shares_menu": "Open Shares menu",
+ "shares": {
+ "add_new_share": "Add new Share",
+ "expires_on": "Expires on {{date}}",
+ "never_expires": "Never expires"
+ }
},
"memory": {
"editor": {
@@ -370,6 +376,12 @@
"memory": {
"try_count": "Tries: {{try_count}}"
}
+ },
+ "share_expired": "Share expired"
+ },
+ "components": {
+ "popover": {
+ "copied_to_clipboard": "Copied to clipboard!"
}
}
}
diff --git a/frontend/src/lib/quiztivity/shares_popover.svelte b/frontend/src/lib/quiztivity/shares_popover.svelte
index 897fbae..1d6e2b0 100644
--- a/frontend/src/lib/quiztivity/shares_popover.svelte
+++ b/frontend/src/lib/quiztivity/shares_popover.svelte
@@ -12,7 +12,7 @@
import SmallPopover from '$lib/components/popover/smalltop.svelte';
import { PopoverTypes } from '$lib/components/popover/smalltop';
import { onMount } from 'svelte';
- import { fade } from 'svelte/transition';
+ import { fade, fly } from 'svelte/transition';
const { t } = getLocalization();
export let open = false;
@@ -72,6 +72,38 @@
onMount(() => {
document.body.addEventListener('keydown', close_start_game_if_esc_is_pressed);
});
+ let never_expires_checked = true;
+ let selected_date = undefined;
+ const create_share = async () => {
+ if (!selected_date && !never_expires_checked) {
+ return;
+ }
+ console.log(selected_date);
+ await fetch('/api/v1/quiztivity/shares/', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ name: undefined,
+ quiztivity: id,
+ expire_in: never_expires_checked
+ ? undefined
+ : Math.floor(Math.abs(new Date() - new Date(selected_date)) / 1000 / 60)
+ })
+ });
+ loaded_shares = load_shares();
+ };
+ let loaded_shares = load_shares();
+
+ const delete_share = async (id: string) => {
+ if (!confirm('Do you really want to delete this Share?')) {
+ return;
+ }
+ await fetch(`/api/v1/quiztivity/shares/${id}`, { method: 'DELETE' });
+ loaded_shares = load_shares();
+ };
+ let add_shares_open = false;
+
{$t('error_page.unknown_error_text')}
{/if} diff --git a/frontend/src/routes/quiztivity/play/+error.svelte b/frontend/src/routes/quiztivity/play/+error.svelte new file mode 100644 index 0000000..10c68eb --- /dev/null +++ b/frontend/src/routes/quiztivity/play/+error.svelte @@ -0,0 +1,53 @@ + + + + + + + ++ {$t('error_page.404_text')} +
+{:else if status === 410} ++ {$t('quiztivity.share_expired')} +
+{:else} ++ {$t('error_page.unknown_error_text')} +
+{/if} + +