diff --git a/Server/Source/Routes/Drafting.ts b/Server/Source/Routes/Drafting.ts
index 7a39911..d4e24a4 100644
--- a/Server/Source/Routes/Drafting.ts
+++ b/Server/Source/Routes/Drafting.ts
@@ -53,9 +53,13 @@ App.post("/upload/midi",
if ((await fromBuffer(Decoded))?.ext !== "mid")
return res.status(400).send("Uploaded MIDI file is not a valid MIDI.");
- if (!await Song.exists({ where: { ID: req.body.TargetSong } }))
+ const SongData = await Song.findOne({ where: { ID: req.body.TargetSong }, relations: { Author: true } })
+ if (!SongData)
return res.status(404).send("The song you're trying to upload a MIDI for does not exist.");
+ if (req.user!.PermissionLevel! < UserPermissions.Administrator && SongData.Author.ID !== req.user!.ID)
+ return res.status(403).send("You don't have permission to upload to this song.");
+
writeFileSync(`./Saved/Songs/${req.body.TargetSong}/Data.mid`, Decoded);
res.send(`${FULL_SERVER_ROOT}/song/download/${req.body.TargetSong}/midi.mid`);
});
@@ -112,9 +116,13 @@ App.post("/upload/audio",
if (!["mp3", "m4a", "ogg", "wav"].includes(ext))
return res.status(404).send("Invalid audio file. (supported: mp3, m4a, ogg, wav)");
- if (!await Song.exists({ where: { ID: req.body.TargetSong } }))
+ const SongData = await Song.findOne({ where: { ID: req.body.TargetSong }, relations: { Author: true } })
+ if (!SongData)
return res.status(404).send("The song you're trying to upload audio for does not exist.");
+ if (req.user!.PermissionLevel! < UserPermissions.Administrator && SongData.Author.ID !== req.user!.ID)
+ return res.status(403).send("You don't have permission to upload to this song.");
+
await writeFileSync(`./Saved/Songs/${req.body.TargetSong}/Audio.${ext}`, Decoded);
ffmpeg()
.input(`./Saved/Songs/${req.body.TargetSong}/Audio.${ext}`)
@@ -142,9 +150,28 @@ App.post("/upload/audio",
App.post("/submit",
RequireAuthentication(),
- ValidateBody(j.object({})),
+ ValidateBody(j.object({
+ TargetSong: j.string().uuid().required()
+ })),
async (req, res) => {
+ const SongData = await Song.findOne({ where: { ID: req.body.TargetSong }, relations: { Author: true } })
+ if (!SongData)
+ return res.status(404).send("The song you're trying to submit for review does not exist.");
+ if (SongData.Author.ID !== req.user!.ID)
+ return res.status(403).send("You don't have permission to submit this song for approval.");
+
+ if (!SongData.IsDraft)
+ return res.status(400).send("This song has already been approved and published.");
+
+ if (SongData.DraftAwaitingReview)
+ return res.status(400).send("You already submitted this song for review.");
+
+ SongData.DraftReviewSubmittedAt = new Date();
+ SongData.DraftAwaitingReview = true;
+ await SongData.save();
+
+ return res.send("Song has been submitted for approval by admins.");
});
export default {
diff --git a/Server/Source/Routes/Library.ts b/Server/Source/Routes/Library.ts
index 8cb7684..ef5f43a 100644
--- a/Server/Source/Routes/Library.ts
+++ b/Server/Source/Routes/Library.ts
@@ -3,6 +3,7 @@ import { RequireAuthentication, ValidateBody } from "../Modules/Middleware";
import { Song } from "../Schemas/Song";
import { OriginalSparks } from "../Modules/FNUtil";
import j from "joi";
+import { UserPermissions } from "../Schemas/User";
const App = Router();
@@ -27,9 +28,13 @@ async (req, res) => {
if (req.user!.Library.findIndex(x => x.SongID.toLowerCase() === req.body.SongID.toLowerCase() || x.Overriding.toLowerCase() === req.body.ToOverride.toLowerCase()) !== -1)
return res.status(400).json({ errorMessage: "This song is already activated." });
- if (!await Song.exists({ where: { ID: req.body.SongID } }))
+ const SongData = await Song.findOne({ where: { ID: req.body.SongID }, relations: { Author: true } });
+ if (!SongData)
return res.status(404).json({ errorMessage: "Provided song doesn't exist." });
+ if (SongData.IsDraft && (req.user!.PermissionLevel < UserPermissions.Administrator && SongData.Author.ID !== req.user!.ID))
+ return res.status(403).json({ errorMessage: "You cannot subscribe to this track, because it's a draft." });
+
req.user!.Library.push({ SongID: req.body.SongID.toLowerCase(), Overriding: req.body.ToOverride.toLowerCase() });
req.user!.save();
@@ -65,7 +70,7 @@ async (req, res) => {
if (!SongData)
return res.status(404).json({ errorMessage: "Provided song doesn't exist." });
- if (SongData.IsDraft && SongData.Author.ID !== req.user.ID)
+ if (SongData.IsDraft && (req.user.PermissionLevel < UserPermissions.Administrator && SongData.Author.ID !== req.user.ID))
return res.status(403).json({ errorMessage: "You cannot subscribe to this track, because it's a draft." });
req.user?.BookmarkedSongs.push(SongData);
@@ -93,12 +98,12 @@ async (req, res) => {
App.get("/song/data/:InternalID",
RequireAuthentication(),
async (req, res) => {
- const SongData = await Song.findOne({ where: { ID: req.params.InternalID }, relations: { Author: true } });
+ const SongData = await Song.findOne({ where: { ID: req.body.SongID }, relations: { Author: true } });
if (!SongData)
return res.status(404).json({ errorMessage: "Provided song doesn't exist." });
- if (SongData.IsDraft && SongData.Author.ID !== req.user!.ID)
- return res.status(403).json({ errorMessage: "You cannot use this track, because it's a draft." });
+ if (SongData.IsDraft && (req.user!.PermissionLevel < UserPermissions.Administrator && SongData.Author.ID !== req.user!.ID))
+ return res.status(403).json({ errorMessage: "You cannot subscribe to this track, because it's a draft." });
res.json(SongData.Package());
})
diff --git a/Server/Source/Schemas/Song.ts b/Server/Source/Schemas/Song.ts
index c30a673..1ac38e6 100644
--- a/Server/Source/Schemas/Song.ts
+++ b/Server/Source/Schemas/Song.ts
@@ -68,6 +68,9 @@ export class Song extends BaseEntity {
@Column({ default: false })
DraftAwaitingReview: boolean;
+ @Column({ nullable: true })
+ DraftReviewSubmittedAt?: Date;
+
@Column()
CreationDate: Date;
diff --git a/src/components/Song.tsx b/src/components/Song.tsx
index 91b735d..eb9a90e 100644
--- a/src/components/Song.tsx
+++ b/src/components/Song.tsx
@@ -9,7 +9,11 @@ export function Song({ data, children }: { data: any, children?: JSX.Element[] |
{data.ArtistName}
{data.Name}
{
- data.IsDraft ? : <>>
+ data.IsDraft ?
+ data.DraftAwaitingReview ?
+ :
+ :
+ <>>
}
{
children ? : <>>
diff --git a/src/routes/AdminSubmissions.tsx b/src/routes/AdminSubmissions.tsx
new file mode 100644
index 0000000..303f4e4
--- /dev/null
+++ b/src/routes/AdminSubmissions.tsx
@@ -0,0 +1,22 @@
+import { useEffect } from "react";
+import { toast } from "react-toastify";
+import axios from "axios";
+
+export function AdminSubmissions() {
+ useEffect(() => {
+ (async () => {
+ const Data = await axios.get("/api/admin/");
+ const Overrides = await axios.get("/api/library/available");
+
+ if (Data.status !== 200 || Overrides.status !== 200)
+ return toast("An error has occured while getting the submitted songs!", { type: "error" });
+
+
+ })();
+ }, []);
+
+ return (
+ <>
+ >
+ )
+}
\ No newline at end of file
diff --git a/src/routes/Profile.tsx b/src/routes/Profile.tsx
index 338285f..57af646 100644
--- a/src/routes/Profile.tsx
+++ b/src/routes/Profile.tsx
@@ -4,7 +4,6 @@ import { PageHeader } from "@primer/react/drafts";
import { useContext, useEffect, useState } from "react";
import { SiteContext } from "../utils/State";
import { useCookies } from "react-cookie";
-import { useNavigate } from "react-router-dom";
import { Song } from "../components/Song";
import axios from "axios";
import { toast } from "react-toastify";
@@ -18,7 +17,6 @@ export function Profile() {
const [draftsSongs, setDraftsSongs] = useState([]);
const [availableOverrides, setAvailableOverrides] = useState<{ Name: string, Template: string }[]>([]);
const [overriding, setOverriding] = useState({});
- const navigate = useNavigate();
useEffect(() => {
(async () => {
@@ -131,18 +129,27 @@ export function Profile() {
{
draftsSongs.length >= 1 ?
- draftsSongs.map(x => {
+ draftsSongs.map((x, i) => {
return
-
+
;
})
diff --git a/src/routes/TrackSubmission.tsx b/src/routes/TrackSubmission.tsx
index 3d7fb9c..876b1e7 100644
--- a/src/routes/TrackSubmission.tsx
+++ b/src/routes/TrackSubmission.tsx
@@ -19,7 +19,7 @@ export function TrackSubmission() {
*/}
Create a New Draft
- Drafts are private versions of Tracks, only available to you. If you want to publish that track, click the "Submit for Review" button on the management page.
+ Drafts are private versions of Tracks, only available to you. If you want to publish that track, click the "Publish" button on the management page.
>
)