From e55ff2d060fe5eedaabd4c2b585cd6436707d715 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 17 Aug 2021 22:22:52 -0400 Subject: [PATCH] Edit w2l result privacy (temporarily breaks delete) --- vocodes/src/common/ApiConfig.ts | 4 + vocodes/src/common/FrontendUrlConfig.ts | 14 ++ vocodes/src/session/SessionWrapper.ts | 14 ++ vocodes/src/v2/NewVocodesContainer.tsx | 7 + .../w2l/w2l_result_edit/W2lResultEditFc.tsx | 183 ++++++++++++++++++ .../w2l/w2l_result_view/W2lResultViewFc.tsx | 52 ++++- 6 files changed, 265 insertions(+), 9 deletions(-) create mode 100644 vocodes/src/v2/w2l/w2l_result_edit/W2lResultEditFc.tsx diff --git a/vocodes/src/common/ApiConfig.ts b/vocodes/src/common/ApiConfig.ts index 4dc04fb840..b21b6df748 100644 --- a/vocodes/src/common/ApiConfig.ts +++ b/vocodes/src/common/ApiConfig.ts @@ -155,6 +155,10 @@ class ApiConfig { return `${this.getScheme()}://${this.getNewApiHost()}/w2l/result/${token}`; } + editW2lInferenceResult(token: string) : string { + return `${this.getScheme()}://${this.getNewApiHost()}/w2l/result/${token}/edit`; + } + deleteW2lInferenceResult(resultToken: string) : string { return `${this.getScheme()}://${this.getNewApiHost()}/w2l/result/${resultToken}/delete`; } diff --git a/vocodes/src/common/FrontendUrlConfig.ts b/vocodes/src/common/FrontendUrlConfig.ts index 731c4223e4..1bfbb79cf0 100644 --- a/vocodes/src/common/FrontendUrlConfig.ts +++ b/vocodes/src/common/FrontendUrlConfig.ts @@ -32,6 +32,20 @@ class FrontendUrlConfig { return `/tts/result/${resultToken}/delete`; } + // W2L template links + + static w2lResultPage(resultToken: string) : string { + return `/w2l/result/${resultToken}`; + } + + static w2lResultEditPage(resultToken: string) : string { + return `/w2l/result/${resultToken}/edit`; + } + + static w2lResultDeletePage(resultToken: string) : string { + return `/w2l/result/${resultToken}/delete`; + } + // User links static userProfilePage(userDisplayName: string) : string { diff --git a/vocodes/src/session/SessionWrapper.ts b/vocodes/src/session/SessionWrapper.ts index 8155a28c00..b0c92bec97 100644 --- a/vocodes/src/session/SessionWrapper.ts +++ b/vocodes/src/session/SessionWrapper.ts @@ -140,6 +140,20 @@ export class SessionWrapper { return this.canDeleteOtherUsersTtsModels(); } + public canEditW2lResultAsUserOrMod(creatorUserToken: MaybeString) : boolean { + if (this.userTokenMatches(creatorUserToken)) { + return true; + } + return this.canDeleteOtherUsersW2lResults(); // TODO: There is no granular permission for this yet. + } + + public canDeleteW2lResultAsUserOrMod(creatorUserToken: MaybeString) : boolean { + if (this.userTokenMatches(creatorUserToken)) { + return true; + } + return this.canDeleteOtherUsersW2lResults(); + } + public userTokenMatches(otherUserToken: MaybeString) : boolean { // Default to false if user token on either side is falsey. if (!otherUserToken) { diff --git a/vocodes/src/v2/NewVocodesContainer.tsx b/vocodes/src/v2/NewVocodesContainer.tsx index bc4db11b31..795909eacd 100644 --- a/vocodes/src/v2/NewVocodesContainer.tsx +++ b/vocodes/src/v2/NewVocodesContainer.tsx @@ -31,6 +31,7 @@ import { W2lTemplateListFc } from './w2l/w2l_template_list/W2lTemplateListFc'; import { W2lTemplateUploadJob } from '../jobs/W2lTemplateUploadJobs'; import { W2lTemplateViewFc } from './w2l/w2l_template_view/W2lTemplateViewFc'; import { TtsResultEditFc } from './tts/tts_result_edit/TtsResultEditFc'; +import { W2lResultEditFc } from './w2l/w2l_result_edit/W2lResultEditFc'; interface Props { sessionWrapper: SessionWrapper, @@ -156,6 +157,12 @@ class NewVocodesContainer extends React.Component { /> + + + + (undefined); + const [visibility, setVisibility] = useState(DEFAULT_VISIBILITY); + + const getW2lResult = useCallback((token) => { + const api = new ApiConfig(); + const endpointUrl = api.viewW2lInferenceResult(token); + + fetch(endpointUrl, { + method: 'GET', + headers: { + 'Accept': 'application/json', + }, + credentials: 'include', + }) + .then(res => res.json()) + .then(res => { + const modelsResponse : W2lInferenceResultResponsePayload = res; + if (!modelsResponse.success) { + return; + } + + setW2lInferenceResult(modelsResponse.result); + setVisibility(modelsResponse?.result?.creator_set_visibility || DEFAULT_VISIBILITY); + }) + .catch(e => { + }); + }, []); + + useEffect(() => { + getW2lResult(token); + }, [token, getW2lResult]); + + const handleVisibilityChange = (ev: React.FormEvent) => { + setVisibility((ev.target as HTMLSelectElement).value) + }; + + const resultLink = FrontendUrlConfig.w2lResultPage(token); + + const handleFormSubmit = (ev: React.FormEvent) => { + ev.preventDefault(); + + if (!w2lInferenceResult) { + return false; + } + + const resultToken = w2lInferenceResult!.w2l_result_token; + + const api = new ApiConfig(); + const endpointUrl = api.editW2lInferenceResult(resultToken); + + const request = { + creator_set_visibility: visibility || DEFAULT_VISIBILITY, + } + + fetch(endpointUrl, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify(request), + }) + .then(res => res.json()) + .then(res => { + if (res === undefined || + !res.success) { + return; // Endpoint error? + } + + history.push(resultLink); + }) + .catch(e => { + }); + + return false; + }; + + let isDisabled = !w2lInferenceResult; + + const visibilityIcon = (visibility === 'public') ? : ; + + return ( +
+

Edit Result Visibility

+ +

+ < Back to result +

+ +
+
+ +
+ +
+ +
+
+ +
+ + + +
+
+ +
+ ) +} + +export { W2lResultEditFc }; + diff --git a/vocodes/src/v2/w2l/w2l_result_view/W2lResultViewFc.tsx b/vocodes/src/v2/w2l/w2l_result_view/W2lResultViewFc.tsx index 8ac89e6f05..a98cf50698 100644 --- a/vocodes/src/v2/w2l/w2l_result_view/W2lResultViewFc.tsx +++ b/vocodes/src/v2/w2l/w2l_result_view/W2lResultViewFc.tsx @@ -3,11 +3,11 @@ import { ApiConfig } from '../../../common/ApiConfig'; import { GravatarFc } from '../../common/GravatarFc'; import { SessionWrapper } from '../../../session/SessionWrapper'; import { useParams, Link } from 'react-router-dom'; -import { W2lResultViewDeleteFc } from './W2lResultView_DeleteFc'; import { ReportDiscordLinkFc } from '../../common/DiscordReportLinkFc'; import { BucketConfig } from '../../../common/BucketConfig'; import { HiddenIconFc } from '../../../icons/HiddenIconFc'; import { VisibleIconFc } from '../../../icons/VisibleIconFc'; +import { FrontendUrlConfig } from '../../../common/FrontendUrlConfig'; interface W2lInferenceResultResponsePayload { success: boolean, @@ -96,7 +96,6 @@ function W2lResultViewFc(props: Props) { let templateName = w2lInferenceResult.template_title; - const currentlyDeleted = !!w2lInferenceResult?.maybe_moderator_fields?.mod_deleted_at || !!w2lInferenceResult?.maybe_moderator_fields?.user_deleted_at; let moderatorRows = null; @@ -165,6 +164,45 @@ function W2lResultViewFc(props: Props) { Hidden : Public ; + const currentlyDeleted = !!w2lInferenceResult?.maybe_moderator_fields?.mod_deleted_at || + !!w2lInferenceResult?.maybe_moderator_fields?.user_deleted_at; + + const deleteButtonTitle = currentlyDeleted ? "Undelete Result?" : "Delete Result?"; + + const deleteButtonCss = currentlyDeleted ? + "button is-warning is-large is-fullwidth" : + "button is-danger is-large is-fullwidth"; + + + let editButton = null; + const canEdit = props.sessionWrapper.canEditW2lResultAsUserOrMod(w2lInferenceResult?.maybe_creator_user_token); + + if (canEdit) { + editButton = ( + <> +
+ Edit Result Visibility + + ); + } + + let deleteButton = null; + const canDelete = props.sessionWrapper.canDeleteW2lResultAsUserOrMod(w2lInferenceResult?.maybe_creator_user_token); + + if (canDelete) { + deleteButton = ( + <> +
+ {deleteButtonTitle} + + ); + } return (

Lipsync Result

@@ -184,7 +222,6 @@ function W2lResultViewFc(props: Props) {

- @@ -236,12 +273,9 @@ function W2lResultViewFc(props: Props) {
- + {editButton} + + {deleteButton}