From 3a50036e40f2c79110307c2fd2832d14e7c513fa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Janis=20Daniel=20Da=CC=88hne?=
 <janis.daehne2@student.uni-halle.de>
Date: Wed, 12 Jun 2019 18:20:27 +0200
Subject: [PATCH] - enter release code has now auto focus - delete release
 dialog now states that deleting a release will also delete all submissions
 and assessments! - performance improvements for creating/editing exercises
 (asset contents are excluded now) - create custom project no longer uses
 assets when frontend sends some

---
 i18n/en.ts                                    |  4 ++--
 i18n/i18nRoot.ts                              |  4 ++--
 .../editCustomProjectLayer.ts                 | 19 +++++++++++++++--
 src/communicationLayer/exerciseEditorLayer.ts | 21 +++++++++++++++++--
 src/components/login/loginForm.tsx            |  5 +++--
 .../dialogs/enterReleaseCodeView.tsx          | 16 ++++++++++++--
 .../dialogs/changeGroupRoleView.tsx           | 10 ++++-----
 .../groupRolesSite/groupRolesCardsView.tsx    |  4 ++--
 .../listView.tsx                              |  2 +-
 .../releasesSite/headerBarContent.tsx         |  2 +-
 .../releasesSite/listView.tsx                 |  8 +++----
 src/helpers/convertersAndTransformers.ts      |  3 ++-
 .../dialog/groupRoleSetAction.ts              |  6 +++---
 .../updateEditorExerciseReducer.ts            |  8 ++++++-
 .../changeGroupRolesDialogReducer.ts          |  2 +-
 .../groupRoleReducer/groupRoleReducer.ts      | 14 ++++++-------
 .../groupRoleReducerValidation.ts             |  2 +-
 .../groupRolesDialogActionTypes.ts            |  2 +-
 src/types/customProjects.ts                   |  3 +++
 src/types/exerciseEditor.ts                   |  2 ++
 src/types/groupRoles.ts                       |  2 +-
 21 files changed, 98 insertions(+), 41 deletions(-)

diff --git a/i18n/en.ts b/i18n/en.ts
index bd6afb6b..e3f77a03 100644
--- a/i18n/en.ts
+++ b/i18n/en.ts
@@ -109,7 +109,7 @@ export const lang_en: LangObj = {
   "Are you sure you want to delete the exercise?": "Are you sure you want to delete the exercise?",
   "Are you sure you want to re-run all automatic assessments?": "Are you sure you want to re-run all automatic assessments?",
   "Delete release": "Delete release",
-  "Are you sure you want to delete the release?": "Are you sure you want to delete the release?",
+  "Are you sure you want to delete the release? This will also delete all submissions (including assessments)!": "Are you sure you want to delete the release? This will also delete all submissions (including assessments)!",
   "Reset password": "Reset password",
   "Are you sure you want to reset the password?": "Are you sure you want to reset the password?",
   "Add users to group": "Add users to group",
@@ -466,7 +466,7 @@ export const lang_en: LangObj = {
   "Can change exercises": "Can change exercises",
   "Can delete exercises": "Can delete exercises",
   "Can lock exercises permanently" : "Can lock exercises permanently",
-  "Can release exercises": "Can release exercises",
+  "Can manage exercise releases": "Can manage exercise releases",
   "Can copy exercises": "Can copy exercises",
   "Can see exercises from other members": "Can see exercises from other members",
   "Can add users to group": "Can add users to group",
diff --git a/i18n/i18nRoot.ts b/i18n/i18nRoot.ts
index e0777d94..8a19ea0c 100644
--- a/i18n/i18nRoot.ts
+++ b/i18n/i18nRoot.ts
@@ -112,7 +112,7 @@ export interface LangObj {
   "Are you sure you want to delete the exercise?": string
   "Are you sure you want to re-run all automatic assessments?": string
   "Delete release": string
-  "Are you sure you want to delete the release?": string
+  "Are you sure you want to delete the release? This will also delete all submissions (including assessments)!": string
   "Reset password": string
   "Are you sure you want to reset the password?": string
   "Add users to group": string
@@ -478,7 +478,7 @@ export interface LangObj {
   "Can change exercises": string
   "Can delete exercises": string
   "Can lock exercises permanently": string
-  "Can release exercises": string
+  "Can manage exercise releases": string
   "Can copy exercises": string
   "Can see exercises from other members": string
   "Can add users to group": string
diff --git a/src/communicationLayer/editCustomProjectLayer.ts b/src/communicationLayer/editCustomProjectLayer.ts
index 931d187d..5cca2793 100644
--- a/src/communicationLayer/editCustomProjectLayer.ts
+++ b/src/communicationLayer/editCustomProjectLayer.ts
@@ -25,8 +25,17 @@ export async function getCustomProject(customProjectId: number): Promise<CustomP
 
 
 export async function createCustomProject(customProject: CustomProjectFullBase): Promise<number> {
+
+  const copy: CustomProjectFullBase = {
+    ...customProject,
+    description: {
+      ...customProject.description,
+      assets: [] //managed via separate api
+    }
+  }
+
   return genericLayer.update<CustomProjectFullBase, number>(callingName,
-    `${controllerPrefix}/create`, customProject)
+    `${controllerPrefix}/create`, copy)
 }
 
 export async function getOwnCustomProjectTestResults(customProjectId: number, pLangId: number): Promise<ReadonlyArray<StoredTestResultFromBackend>> {
@@ -46,8 +55,14 @@ export async function updateCustomProjectSolution(customProjectId: number, solut
 }
 
 export async function updateCustomProjectDescription(customProjectId: number, description: CustomProjectDescriptionFullBase): Promise<void> {
+
+  const copy: CustomProjectDescriptionFullBase = {
+    ...description,
+    assets: [] //managed via separate api
+  }
+
   return genericLayer.update<CustomProjectDescriptionFullBase, void>(callingName,
-    `${controllerPrefix}/update/${customProjectId}/description`, description)
+    `${controllerPrefix}/update/${customProjectId}/description`, copy)
 }
 
 
diff --git a/src/communicationLayer/exerciseEditorLayer.ts b/src/communicationLayer/exerciseEditorLayer.ts
index 31bb91c4..430c6b01 100644
--- a/src/communicationLayer/exerciseEditorLayer.ts
+++ b/src/communicationLayer/exerciseEditorLayer.ts
@@ -35,9 +35,18 @@ export async function getEditorExerciseWithData(exerciseId: number): Promise<Exe
  * instead navigate to load exercise and load the given number (exercise id)
  */
 export async function createEditorExercise(exercise: EditorExerciseForBackend): Promise<number> {
+
+  const copy: EditorExerciseForBackend = {
+    ...exercise,
+    exerciseDescription: {
+      ...exercise.exerciseDescription,
+      assets: []
+    }
+  }
+
   return genericLayer.create<EditorExerciseForBackend, number>(callingName,
                                                                `${controllerPrefixExerciseEditor}/create`,
-                                                               exercise
+                                                               copy
   )
 }
 
@@ -46,9 +55,17 @@ export async function createEditorExercise(exercise: EditorExerciseForBackend):
  * @param exercise the exercise to create
  */
 export async function updateEditorExercise(exercise: EditorExerciseForBackend): Promise<EditorExerciseFromBackend> {
+
+  const copy: EditorExerciseForBackend = {
+    ...exercise,
+    exerciseDescription: {
+      ...exercise.exerciseDescription,
+      assets: []
+    }
+  }
   return genericLayer.update<EditorExerciseForBackend, EditorExerciseFromBackend>(callingName,
                                                                                   `${controllerPrefixExerciseEditor}/update`,
-                                                                                  exercise
+                                                                                  copy
   )
 }
 
diff --git a/src/components/login/loginForm.tsx b/src/components/login/loginForm.tsx
index a2b92afa..528b51b6 100644
--- a/src/components/login/loginForm.tsx
+++ b/src/components/login/loginForm.tsx
@@ -211,8 +211,9 @@ class LoginForm extends React.Component<Props, any> {
                                    placeholder="e.g. abcef"
                                    value={this.props.id}
                                    onChange={(e) => this.idChanged(e)}
-                                   ref={(input) => {
-                                     if (input) {
+                                   ref={(inputComponent) => {
+
+                                     if (inputComponent) {
                                        const field = document.getElementById(loginFieldId)
                                        const fieldPw = document.getElementById(loginFieldPwId)
 
diff --git a/src/components/sites/allAccessibleExercisesSite/dialogs/enterReleaseCodeView.tsx b/src/components/sites/allAccessibleExercisesSite/dialogs/enterReleaseCodeView.tsx
index 50e7d59d..d976e25f 100644
--- a/src/components/sites/allAccessibleExercisesSite/dialogs/enterReleaseCodeView.tsx
+++ b/src/components/sites/allAccessibleExercisesSite/dialogs/enterReleaseCodeView.tsx
@@ -48,6 +48,8 @@ const stateProps = returntypeof(mapStateToProps);
 const dispatchProps = returntypeof(mapDispatchToProps);
 type Props = typeof stateProps & typeof dispatchProps;
 
+const enterReleaseCodeInputId = 'enterReleaseCodeInputId'
+
 class EnterReleaseCodeView extends React.Component<Props, any> {
   render(): JSX.Element {
     return (
@@ -63,7 +65,8 @@ class EnterReleaseCodeView extends React.Component<Props, any> {
                 }
               </label>
               <div className="two-flexed-stretch-left">
-                <MaterialInput className="mar-right"
+                <MaterialInput id={enterReleaseCodeInputId}
+                               className="mar-right"
                                value={this.props.dialogState.releaseCode}
                                onChange={(e) => this.props.setReleaseCode(e.currentTarget.value)}
                                onKeyPress={async (e) => {
@@ -79,6 +82,15 @@ class EnterReleaseCodeView extends React.Component<Props, any> {
                                }}
                                validations={validationRules.releaseCode}
                                validationMessageKey={validationMessageKeys.releaseCode}
+                               ref={(inputComponent) => {
+
+                                 if (inputComponent) {
+                                   const inputReleaseCode = document.getElementById(enterReleaseCodeInputId)
+
+                                   if (inputReleaseCode) inputReleaseCode.focus()
+                                 }
+
+                               }}
                 />
               </div>
             </Form.Field>
@@ -90,4 +102,4 @@ class EnterReleaseCodeView extends React.Component<Props, any> {
   }
 }
 
-export default connect(mapStateToProps, mapDispatchToProps)(EnterReleaseCodeView)
\ No newline at end of file
+export default connect(mapStateToProps, mapDispatchToProps)(EnterReleaseCodeView)
diff --git a/src/components/sites/groupRolesSite/dialogs/changeGroupRoleView.tsx b/src/components/sites/groupRolesSite/dialogs/changeGroupRoleView.tsx
index 0137ce9e..29dd9353 100644
--- a/src/components/sites/groupRolesSite/dialogs/changeGroupRoleView.tsx
+++ b/src/components/sites/groupRolesSite/dialogs/changeGroupRoleView.tsx
@@ -16,7 +16,7 @@ import {
   setCanChangeOtherMembersRole,
   setCanCreateExercises,
   setCanDeleteExercises, setCanLockExercisesPermanently,
-  setCanReleaseExercises,
+  setCanManageExerciseReleases,
   setCanRemoveMemberFromGroup,
   setCanSeeExercisesFromOthersInGroup,
   setCanSeeOtherMembers,
@@ -54,7 +54,7 @@ const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({
                                                                         setCanChangeExercises,
                                                                         setCanDeleteExercises,
                                                                         setCanLockExercisesPermanently,
-                                                                        setCanReleaseExercises,
+                                                                        setCanManageExerciseReleases,
                                                                         setCanAssessExercises,
                                                                         setCanSeeExercisesFromOthersInGroup,
                                                                         setCanAddUserToGroup,
@@ -134,10 +134,10 @@ class ChangeGroupRoleView extends React.Component<Props, any> {
             </Form.Field>
             <Form.Field>
               <Form.Field>
-                <Checkbox label={getI18n(this.props.langId, 'Can release exercises')}
-                          checked={this.props.groupRole.canReleaseExercises}
+                <Checkbox label={getI18n(this.props.langId, 'Can manage exercise releases')}
+                          checked={this.props.groupRole.canManageExerciseReleases}
                           onChange={(e, data) => {
-                            this.props.setCanReleaseExercises(data.checked)
+                            this.props.setCanManageExerciseReleases(data.checked)
                           }}
                 />
               </Form.Field>
diff --git a/src/components/sites/groupRolesSite/groupRolesCardsView.tsx b/src/components/sites/groupRolesSite/groupRolesCardsView.tsx
index ba2a163b..68869ad4 100644
--- a/src/components/sites/groupRolesSite/groupRolesCardsView.tsx
+++ b/src/components/sites/groupRolesSite/groupRolesCardsView.tsx
@@ -78,8 +78,8 @@ class GroupRolesCardsView extends React.Component<Props, any> {
 
                         <Divider/>
 
-                        <Checkbox label={getI18n(this.props.langId, 'Can release exercises')}
-                                  disabled checked={groupRole.canReleaseExercises}/>
+                        <Checkbox label={getI18n(this.props.langId, 'Can manage exercise releases')}
+                                  disabled checked={groupRole.canManageExerciseReleases}/>
                         <Checkbox label={getI18n(this.props.langId, 'Can see exercises from other members')} disabled
                                   checked={groupRole.canSeeExercisesFromOthersInGroup}/>
 
diff --git a/src/components/sites/manageOwnOrGroupExerciseComponents/listView.tsx b/src/components/sites/manageOwnOrGroupExerciseComponents/listView.tsx
index 958ce741..83c5b6c4 100644
--- a/src/components/sites/manageOwnOrGroupExerciseComponents/listView.tsx
+++ b/src/components/sites/manageOwnOrGroupExerciseComponents/listView.tsx
@@ -635,7 +635,7 @@ class TableView extends React.Component<Props, any> {
                     <Table.Cell>
                       {
                         (this.props.currentUserGroupRole === null
-                          || this.props.currentUserGroupRole.canReleaseExercises
+                          || this.props.currentUserGroupRole.canManageExerciseReleases
                           || this.props.currentUserGroupRole.canAssessExercises) &&
                         <div>
                           <Link to={constants.getExerciseReleaseLinkPath(exercisePreview.id,
diff --git a/src/components/sites/manageOwnOrGroupExerciseComponents/releasesSite/headerBarContent.tsx b/src/components/sites/manageOwnOrGroupExerciseComponents/releasesSite/headerBarContent.tsx
index 6dffcdf4..5de388c7 100644
--- a/src/components/sites/manageOwnOrGroupExerciseComponents/releasesSite/headerBarContent.tsx
+++ b/src/components/sites/manageOwnOrGroupExerciseComponents/releasesSite/headerBarContent.tsx
@@ -59,7 +59,7 @@ class HeaderBar extends React.Component<Props, any> {
       <div>
 
         {
-          ((this.props.groupRole && this.props.groupRole.canReleaseExercises) || this.props.comesFromOwnExercisesSite) &&
+          ((this.props.groupRole && this.props.groupRole.canManageExerciseReleases) || this.props.comesFromOwnExercisesSite) &&
           this.props.exercisesPreview !== null && this.props.exercisesPreview.isPermanentlyLocked === false &&
           <div className="clickable"
                onClick={() => {
diff --git a/src/components/sites/manageOwnOrGroupExerciseComponents/releasesSite/listView.tsx b/src/components/sites/manageOwnOrGroupExerciseComponents/releasesSite/listView.tsx
index 4a12fd5b..be3efd74 100644
--- a/src/components/sites/manageOwnOrGroupExerciseComponents/releasesSite/listView.tsx
+++ b/src/components/sites/manageOwnOrGroupExerciseComponents/releasesSite/listView.tsx
@@ -267,7 +267,7 @@ class ListView extends React.Component<Props, any> {
 
                   editNode = <HelpPopup defaultText={getI18n(this.props.langId, "Exercise is lock")}/>
 
-                } else if (((this.props.groupRole && this.props.groupRole.canReleaseExercises) || this.props.comesFromOwnExercisesSite) &&
+                } else if (((this.props.groupRole && this.props.groupRole.canManageExerciseReleases) || this.props.comesFromOwnExercisesSite) &&
                   (exerciseRelease.hasAutomaticAssessmentStarted === false || exerciseRelease.hasAutomaticAssessmentFinished) &&
                   (this.props.exercises !== null && this.props.exercises.isPermanentlyLocked === false)) {
 
@@ -279,7 +279,7 @@ class ListView extends React.Component<Props, any> {
                     <Icon name="write"/>
                   </div>)
 
-                } else if (((this.props.groupRole && this.props.groupRole.canReleaseExercises) || this.props.comesFromOwnExercisesSite) &&
+                } else if (((this.props.groupRole && this.props.groupRole.canManageExerciseReleases) || this.props.comesFromOwnExercisesSite) &&
                   (exerciseRelease.hasAutomaticAssessmentStarted === true && exerciseRelease.hasAutomaticAssessmentFinished === false) &&
                   (this.props.exercises !== null && this.props.exercises.isPermanentlyLocked === false)) {
 
@@ -297,7 +297,7 @@ class ListView extends React.Component<Props, any> {
 
                   editNode = <HelpPopup defaultText={getI18n(this.props.langId, "Exercise is lock")}/>
 
-                } else if ((this.props.groupRole && this.props.groupRole.canReleaseExercises) || this.props.comesFromOwnExercisesSite) {
+                } else if ((this.props.groupRole && this.props.groupRole.canManageExerciseReleases) || this.props.comesFromOwnExercisesSite) {
 
                   deleteNode = (<div className="clickable"
                                      onClick={async () => {
@@ -305,7 +305,7 @@ class ListView extends React.Component<Props, any> {
                                        const shouldRemove = await askDialog(
                                          getI18n(this.props.langId, 'Delete release'),
                                          `${getI18n(this.props.langId,
-                                                    'Are you sure you want to delete the release?'
+                                                    'Are you sure you want to delete the release? This will also delete all submissions (including assessments)!'
                                          )} (${exerciseRelease.generatedCode})`,
                                          this.props.langId
                                        )
diff --git a/src/helpers/convertersAndTransformers.ts b/src/helpers/convertersAndTransformers.ts
index ebcff878..15c20fc3 100644
--- a/src/helpers/convertersAndTransformers.ts
+++ b/src/helpers/convertersAndTransformers.ts
@@ -54,9 +54,10 @@ import globalState from '../state/state'
 export function convertSizeToHumanReadableSize(bytes: number, decimals = 0): string {
   if (bytes === 0) return '0 Byte'
   const k = 1024
-  const dm = decimals + 1 || 3
+  const dm = decimals < 0 ? 0 : decimals;
   const sizes: ReadonlyArray<string> = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
   const i = Math.floor(Math.log(bytes) / Math.log(k))
+  //parse float avaids trailing zeros
   return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`
 }
 
diff --git a/src/state/actions/groupRolesSite/dialog/groupRoleSetAction.ts b/src/state/actions/groupRolesSite/dialog/groupRoleSetAction.ts
index 8c9d4fd5..5fdb7d07 100644
--- a/src/state/actions/groupRolesSite/dialog/groupRoleSetAction.ts
+++ b/src/state/actions/groupRolesSite/dialog/groupRoleSetAction.ts
@@ -9,7 +9,7 @@ import {
   SET_canChangeOtherMembersRoleAction,
   SET_canCreateExercisesAction,
   SET_canDeleteExercisesAction, SET_canLockExercisesPermanentlyAction,
-  SET_canReleaseExercisesAction,
+  SET_canManageExerciseReleasesAction,
   SET_canRemoveMemberFromGroupAction,
   SET_canSeeExercisesFromOthersInGroupAction,
   SET_canSeeOtherMembersAction,
@@ -72,9 +72,9 @@ export function setCanLockExercisesPermanently(can: boolean): SET_canLockExercis
   }
 }
 
-export function setCanReleaseExercises(can: boolean): SET_canReleaseExercisesAction {
+export function setCanManageExerciseReleases(can: boolean): SET_canManageExerciseReleasesAction {
   return {
-    type: ActionType.SET_canReleaseExercises,
+    type: ActionType.SET_canManageExerciseReleases,
     can
   }
 }
diff --git a/src/state/reducers/exerciseEditorSite/updateEditorExerciseReducer.ts b/src/state/reducers/exerciseEditorSite/updateEditorExerciseReducer.ts
index 2fea5355..eb0fb036 100644
--- a/src/state/reducers/exerciseEditorSite/updateEditorExerciseReducer.ts
+++ b/src/state/reducers/exerciseEditorSite/updateEditorExerciseReducer.ts
@@ -57,7 +57,13 @@ export function reducer(state: State = initial(), action: AllActions): State {
       return {
         ...state,
         isLoading: false,
-        editorExercise: convertEditorExerciseFromBackendToFrontend(action.payload),
+        editorExercise: {
+          ...convertEditorExerciseFromBackendToFrontend(action.payload),
+          exerciseDescription: {
+            ...action.payload.exerciseDescription,
+            assets: state.editorExercise.exerciseDescription.assets //assets are not included on update!!
+          }
+        },
         oldGroupId: action.payload.exerciseProperties.userGroupId,
         oldIsOnlyVisibleToMe: action.payload.exerciseProperties.isOnlyVisibleToMe,
         numReleases: action.payload.numReleases
diff --git a/src/state/reducers/groupRolesSite/groupRoleReducer/changeGroupRolesDialogReducer.ts b/src/state/reducers/groupRolesSite/groupRoleReducer/changeGroupRolesDialogReducer.ts
index 3e095e5b..0f16bc9c 100644
--- a/src/state/reducers/groupRolesSite/groupRoleReducer/changeGroupRolesDialogReducer.ts
+++ b/src/state/reducers/groupRolesSite/groupRoleReducer/changeGroupRolesDialogReducer.ts
@@ -75,7 +75,7 @@ export function reducer(state: State = initial, action: AllActions): State {
     case ActionType.SET_canChangeExercises:
     case ActionType.SET_canDeleteExercises:
     case ActionType.SET_canLockExercisesPermanently:
-    case ActionType.SET_canReleaseExercises:
+    case ActionType.SET_canManageExerciseReleases:
     case ActionType.SET_canAssessExercises:
     case ActionType.SET_canSeeExercisesFromOthersInGroup:
     case ActionType.SET_canAddUserToGroup:
diff --git a/src/state/reducers/groupRolesSite/groupRoleReducer/groupRoleReducer.ts b/src/state/reducers/groupRolesSite/groupRoleReducer/groupRoleReducer.ts
index e106b41a..05009bbe 100644
--- a/src/state/reducers/groupRolesSite/groupRoleReducer/groupRoleReducer.ts
+++ b/src/state/reducers/groupRolesSite/groupRoleReducer/groupRoleReducer.ts
@@ -21,7 +21,7 @@ export const initial: State = {
   canDeleteExercises: false,
   canLockExercisesPermanently: false,
 
-  canReleaseExercises: false,
+  canManageExerciseReleases: false,
   canAssessExercises: false,
 
   canSeeExercisesFromOthersInGroup: false,
@@ -42,7 +42,7 @@ export const validationRules = getValidationCollection<State>({
                                                                 canDeleteExercises: [],
                                                                 canLockExercisesPermanently: [],
 
-                                                                canReleaseExercises: [],
+                                                                canManageExerciseReleases: [],
                                                                 canAssessExercises: [],
 
                                                                 canSeeExercisesFromOthersInGroup: [],
@@ -95,8 +95,8 @@ export interface SET_canLockExercisesPermanentlyAction extends ActionBase {
   readonly can: boolean
 }
 
-export interface SET_canReleaseExercisesAction extends ActionBase {
-  readonly type: ActionType.SET_canReleaseExercises
+export interface SET_canManageExerciseReleasesAction extends ActionBase {
+  readonly type: ActionType.SET_canManageExerciseReleases
   readonly can: boolean
 }
 
@@ -144,7 +144,7 @@ export type AllActions =
   | SET_canChangeExercisesAction
   | SET_canDeleteExercisesAction
   | SET_canLockExercisesPermanentlyAction
-  | SET_canReleaseExercisesAction
+  | SET_canManageExerciseReleasesAction
   | SET_canAssessExercisesAction
   | SET_canSeeExercisesFromOthersInGroupAction
   | SET_canAddUserToGroupAction
@@ -202,10 +202,10 @@ export function reducer(state: State = initial, action: AllActions): State {
         canLockExercisesPermanently: action.can
       }
 
-    case ActionType.SET_canReleaseExercises:
+    case ActionType.SET_canManageExerciseReleases:
       return {
         ...state,
-        canReleaseExercises: action.can
+        canManageExerciseReleases: action.can
       }
 
     case ActionType.SET_canAssessExercises:
diff --git a/src/state/reducers/groupRolesSite/groupRoleReducer/groupRoleReducerValidation.ts b/src/state/reducers/groupRolesSite/groupRoleReducer/groupRoleReducerValidation.ts
index 17d63282..413335ab 100644
--- a/src/state/reducers/groupRolesSite/groupRoleReducer/groupRoleReducerValidation.ts
+++ b/src/state/reducers/groupRolesSite/groupRoleReducer/groupRoleReducerValidation.ts
@@ -12,7 +12,7 @@ export const validationMessageKeys = getValidationMessagesCollection<State>({
   canDeleteExercises: '',
   canLockExercisesPermanently: '',
 
-  canReleaseExercises: '',
+  canManageExerciseReleases: '',
   canAssessExercises: '',
 
   canSeeExercisesFromOthersInGroup: '',
diff --git a/src/state/reducers/groupRolesSite/groupRoleReducer/groupRolesDialogActionTypes.ts b/src/state/reducers/groupRolesSite/groupRoleReducer/groupRolesDialogActionTypes.ts
index 497136fe..e16cce9a 100644
--- a/src/state/reducers/groupRolesSite/groupRoleReducer/groupRolesDialogActionTypes.ts
+++ b/src/state/reducers/groupRolesSite/groupRoleReducer/groupRolesDialogActionTypes.ts
@@ -22,7 +22,7 @@ export enum ActionType {
   SET_canChangeExercises = 'groupRolesChangeDialogReducer_SET_canChangeExercises',
   SET_canDeleteExercises = 'groupRolesChangeDialogReducer_SET_canDeleteExercises',
   SET_canLockExercisesPermanently = 'groupRolesChangeDialogReducer_SET_canLockExercisesPermanently',
-  SET_canReleaseExercises = 'groupRolesChangeDialogReducer_SET_canReleaseExercises',
+  SET_canManageExerciseReleases = 'groupRolesChangeDialogReducer_SET_canManageExerciseReleases',
   SET_canAssessExercises = 'groupRolesChangeDialogReducer_SET_canAssessExercises',
   SET_canSeeExercisesFromOthersInGroup = 'groupRolesChangeDialogReducer_SET_canSeeExercisesFromOthersInGroup',
   SET_canAddUserToGroup = 'groupRolesChangeDialogReducer_SET_canAddUserToGroup',
diff --git a/src/types/customProjects.ts b/src/types/customProjects.ts
index c9ab86e9..b3cf8745 100644
--- a/src/types/customProjects.ts
+++ b/src/types/customProjects.ts
@@ -62,6 +62,9 @@ export interface CustomProjectFrontendExclusive extends CustomProjectBase {
 export interface CustomProjectDescriptionFullBase {
   readonly id: number
   readonly content: string
+  /**
+   * FROM frontend to backend this should be empty!
+   */
   readonly assets: ReadonlyArray<FileWithData>
 }
 
diff --git a/src/types/exerciseEditor.ts b/src/types/exerciseEditor.ts
index 468c3586..377d1c9b 100644
--- a/src/types/exerciseEditor.ts
+++ b/src/types/exerciseEditor.ts
@@ -180,6 +180,8 @@ export interface ExerciseDescriptionFullBase {
   /**
    * the assets (files) are only send from backend to frontend
    * frontend need to add these through separate requests!
+   *
+   * FROM frontend to backend this should be always empty (not needed)!
    */
   readonly assets: ReadonlyArray<FileWithData>
 }
diff --git a/src/types/groupRoles.ts b/src/types/groupRoles.ts
index 4097e31a..49b38679 100644
--- a/src/types/groupRoles.ts
+++ b/src/types/groupRoles.ts
@@ -23,7 +23,7 @@ export interface GroupRoleWithPermissionFullBase extends GroupRoleFullBase {
   readonly canDeleteExercises: boolean
   readonly canLockExercisesPermanently: boolean
 
-  readonly canReleaseExercises: boolean
+  readonly canManageExerciseReleases: boolean
   readonly canAssessExercises: boolean
 
   readonly canSeeExercisesFromOthersInGroup: boolean
-- 
GitLab