s
This commit is contained in:
parent
017b619766
commit
2bd4203827
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
})
|
||||
|
|
|
@ -68,6 +68,9 @@ export class Song extends BaseEntity {
|
|||
@Column({ default: false })
|
||||
DraftAwaitingReview: boolean;
|
||||
|
||||
@Column({ nullable: true })
|
||||
DraftReviewSubmittedAt?: Date;
|
||||
|
||||
@Column()
|
||||
CreationDate: Date;
|
||||
|
||||
|
|
|
@ -9,7 +9,11 @@ export function Song({ data, children }: { data: any, children?: JSX.Element[] |
|
|||
<Text sx={{ display: "block", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap" }}>{data.ArtistName}</Text>
|
||||
<Text sx={{ display: "block", textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap" }}><b>{data.Name}</b></Text>
|
||||
{
|
||||
data.IsDraft ? <Label variant="danger">Draft - not published</Label> : <></>
|
||||
data.IsDraft ?
|
||||
data.DraftAwaitingReview ?
|
||||
<Label variant="attention">Draft - awaiting review</Label> :
|
||||
<Label variant="danger">Draft - not published</Label> :
|
||||
<></>
|
||||
}
|
||||
{
|
||||
children ? <Divider /> : <></>
|
||||
|
|
22
src/routes/AdminSubmissions.tsx
Normal file
22
src/routes/AdminSubmissions.tsx
Normal file
|
@ -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 (
|
||||
<>
|
||||
</>
|
||||
)
|
||||
}
|
|
@ -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<unknown[]>([]);
|
||||
const [availableOverrides, setAvailableOverrides] = useState<{ Name: string, Template: string }[]>([]);
|
||||
const [overriding, setOverriding] = useState<unknown>({});
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
|
@ -131,18 +129,27 @@ export function Profile() {
|
|||
<Box className="songCategory">
|
||||
{
|
||||
draftsSongs.length >= 1 ?
|
||||
draftsSongs.map(x => {
|
||||
draftsSongs.map((x, i) => {
|
||||
return <Song data={x}>
|
||||
<Button sx={{ width: "100%", marginBottom: 1 }} variant="primary" onClick={() => { setIsActivateDialogOpen(true); setOverriding(x) }} disabled={librarySongs.findIndex(y => y.ID === x.ID) !== -1}>Add to Active</Button>
|
||||
<Button sx={{ width: "100%", marginBottom: 1 }}>Publish</Button>
|
||||
<Button sx={{ width: "100%", marginBottom: 1 }} onClick={async () => {
|
||||
const Res = await axios.post("/api/drafts/submit", { TargetSong: x.ID });
|
||||
if (Res.status === 200) {
|
||||
x.DraftAwaitingReview = true;
|
||||
draftsSongs[i] = x;
|
||||
setDraftsSongs([...draftsSongs]);
|
||||
}
|
||||
else
|
||||
toast(Res.data, { type: "error" });
|
||||
}}>Publish</Button>
|
||||
<Button sx={{ width: "100%" }} variant="danger" onClick={async () => {
|
||||
const Res = await axios.post("/api/drafts/delete", { SongID: x.ID });
|
||||
const Res = await axios.post("/api/drafts/delete", { TargetSong: x.ID });
|
||||
if (Res.status === 200) {
|
||||
draftsSongs.splice(draftsSongs.findIndex(y => y.ID === x.ID), 1);
|
||||
setDraftsSongs([...draftsSongs]);
|
||||
}
|
||||
else
|
||||
toast(Res.data.errorMessage, { type: "error" })
|
||||
toast(Res.data, { type: "error" });
|
||||
}}>Unsubscribe</Button>
|
||||
</Song>;
|
||||
})
|
||||
|
|
|
@ -19,7 +19,7 @@ export function TrackSubmission() {
|
|||
<Text></Text>
|
||||
</Box>*/}
|
||||
<Heading>Create a New Draft</Heading>
|
||||
<Text>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.</Text>
|
||||
<Text>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.</Text>
|
||||
<form method="GET" action="" ref={formRef}>
|
||||
<FormControl required={true} sx={formControlStyle}>
|
||||
<FormControl.Label>Song Name</FormControl.Label>
|
||||
|
@ -95,7 +95,7 @@ export function TrackSubmission() {
|
|||
<FormControl.Caption>This will play in the background of your song. Make sure it was exported from REAPER.</FormControl.Caption>
|
||||
</FormControl>
|
||||
<FormControl required={true} sx={formControlStyle}>
|
||||
<FormControl.Label>Cover Image (.jpg, .jpeg, .webp, .png)</FormControl.Label>
|
||||
<FormControl.Label>Cover Image (.png)</FormControl.Label>
|
||||
<TextInput type="file" />
|
||||
<FormControl.Caption>Must be a 1:1 ratio. Max: 2048x2048, min: 512x512</FormControl.Caption>
|
||||
</FormControl>
|
||||
|
@ -165,16 +165,14 @@ export function TrackSubmission() {
|
|||
return;
|
||||
|
||||
const MidiRes = await axios.post("/api/drafts/upload/midi", { Data: Buffer.from(await Midi.arrayBuffer()).toString("hex"), TargetSong: SongData.data.ID });
|
||||
toast(MidiRes.status === 200 ? "Uploaded MIDI chart successfully." : MidiRes.data.errorMessage, { type: MidiRes.status === 200 ? "success" : "error" });
|
||||
toast(MidiRes.status === 200 ? "Uploaded MIDI chart successfully." : MidiRes.data, { type: MidiRes.status === 200 ? "success" : "error" });
|
||||
|
||||
const AudioRes = await axios.post("/api/drafts/upload/audio", { Data: Buffer.from(await Music.arrayBuffer()).toString("hex"), TargetSong: SongData.data.ID });
|
||||
toast(AudioRes.status === 200 ? "Uploaded audio for processing successfully." : AudioRes.data.errorMessage, { type: AudioRes.status === 200 ? "success" : "error" });
|
||||
toast(AudioRes.status === 200 ? "Uploaded audio for processing successfully." : AudioRes.data, { type: AudioRes.status === 200 ? "success" : "error" });
|
||||
|
||||
const CoverRes = await axios.post("/api/drafts/upload/cover", { Data: Buffer.from(await Cover.arrayBuffer()).toString("hex"), TargetSong: SongData.data.ID });
|
||||
toast(MidiRes.status === 200 ? "Uploaded cover image successfully." : MidiRes.data.errorMessage, { type: CoverRes.status === 200 ? "success" : "error" });
|
||||
toast(CoverRes.status === 200 ? "Uploaded cover image successfully." : CoverRes.data, { type: CoverRes.status === 200 ? "success" : "error" });
|
||||
}}>Create</Button>
|
||||
|
||||
|
||||
</form>
|
||||
</>
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue
Block a user