From 05bda8ee824580d39386574fd8910b3b470d863f Mon Sep 17 00:00:00 2001
From: "robinwilliam.hundt" <robinwilliam.hundt@stud.uni-goettingen.de>
Date: Sat, 29 Sep 2018 13:26:38 +0200
Subject: [PATCH] fixed #121 and made small changes to studentPage

Solution is no longer displayed on student page because it may contain grading information which has been changed during the grading process and would thus confuse the student
---
 core/serializers/submission.py                | 10 +++++--
 core/tests/test_student_page.py               |  6 ++--
 core/views/common_views.py                    |  4 +--
 frontend/src/api.ts                           |  2 +-
 frontend/src/components/SubmissionType.vue    | 25 +++++++++-------
 .../components/student/ExamInformation.vue    | 13 ++++++--
 .../src/components/student/SubmissionList.vue |  4 +--
 .../student_list/StudentListMenu.vue          |  2 +-
 frontend/src/models.ts                        |  2 +-
 .../pages/base/TutorReviewerBaseLayout.vue    |  2 +-
 frontend/src/pages/student/StudentLayout.vue  | 12 ++++----
 frontend/src/pages/student/StudentPage.vue    |  9 ++----
 .../pages/student/StudentSubmissionPage.vue   |  3 +-
 frontend/src/store/actions.ts                 | 30 ++++++++-----------
 14 files changed, 65 insertions(+), 59 deletions(-)

diff --git a/core/serializers/submission.py b/core/serializers/submission.py
index 8366d173..a879560b 100644
--- a/core/serializers/submission.py
+++ b/core/serializers/submission.py
@@ -17,8 +17,14 @@ class SubmissionNoTextFieldsSerializer(DynamicFieldsModelSerializer):
         fields = ('pk', 'type', 'score', 'final', 'full_score')
 
 
-class SubmissionSerializer(DynamicFieldsModelSerializer):
-    type = SubmissionTypeSerializer()
+class StudentSubmissionSerializer(DynamicFieldsModelSerializer):
+    type = SubmissionTypeSerializer(
+        # exclude solution from Type information
+        fields=(('pk',
+                 'name',
+                 'full_score',
+                 'description',
+                 'programming_language')))
     feedback = VisibleCommentFeedbackSerializer()
     tests = TestSerializer(many=True)
 
diff --git a/core/tests/test_student_page.py b/core/tests/test_student_page.py
index fa57aea9..41800def 100644
--- a/core/tests/test_student_page.py
+++ b/core/tests/test_student_page.py
@@ -209,10 +209,8 @@ class StudentSelfSubmissionsTests(APITestCase):
             self.submission_list_first_entry['type']['description'],
             self.student_info.submissions.first().type.description)
 
-    def test_submission_data_contains_solution(self):
-        self.assertEqual(
-            self.submission_list_first_entry['type']['solution'],
-            self.student_info.submissions.first().type.solution)
+    def test_submission_data_not_contains_solution(self):
+        self.assertNotIn('solution', self.submission_list_first_entry['type'])
 
     def test_submission_data_contains_final_status(self):
         self.assertEqual(
diff --git a/core/views/common_views.py b/core/views/common_views.py
index ea2fdccb..ad08eb76 100644
--- a/core/views/common_views.py
+++ b/core/views/common_views.py
@@ -22,7 +22,7 @@ from core.models import ExamType, StudentInfo, SubmissionType
 from core.permissions import IsReviewer, IsStudent, IsTutorOrReviewer
 from core.serializers import (ExamSerializer, StudentInfoSerializer,
                               StudentInfoForListViewSerializer,
-                              SubmissionNoTypeSerializer, SubmissionSerializer,
+                              SubmissionNoTypeSerializer, StudentSubmissionSerializer,
                               SubmissionTypeSerializer, TutorSerializer,
                               UserAccountSerializer)
 
@@ -54,7 +54,7 @@ class StudentSelfApiView(generics.RetrieveAPIView):
 
 class StudentSelfSubmissionsApiView(generics.ListAPIView):
     permission_classes = (IsStudent, )
-    serializer_class = SubmissionSerializer
+    serializer_class = StudentSubmissionSerializer
 
     def get_queryset(self):
         return self.request.user.student.submissions
diff --git a/frontend/src/api.ts b/frontend/src/api.ts
index fbc5f1d5..20d6b66e 100644
--- a/frontend/src/api.ts
+++ b/frontend/src/api.ts
@@ -68,7 +68,7 @@ export async function fetchAllStudents (): Promise<Array<StudentInfoForListView>
   return (await ax.get(url)).data
 }
 
-export async function fetchStudent ({pk, }:
+export async function fetchStudent ({pk}:
 {pk: string}): Promise<StudentInfoForListView> {
   const url = `/api/student/${pk}/`
   return (await ax.get(url)).data
diff --git a/frontend/src/components/SubmissionType.vue b/frontend/src/components/SubmissionType.vue
index 77baa06c..c1364165 100644
--- a/frontend/src/components/SubmissionType.vue
+++ b/frontend/src/components/SubmissionType.vue
@@ -18,12 +18,12 @@
               ></span>
             </v-card-text>
           </v-card>
-          <v-flex v-else-if="item.title === 'Solution'">
-          <pre
-            class="elevation-2 solution-code pl-2"
-            :class="programmingLanguage"
-          ><span v-html="highlightedSolution"></span></pre>
-          </v-flex>
+          <div v-else-if="item.title === 'Solution'">
+            <pre
+              class="elevation-2 solution-code pl-2"
+              :class="programmingLanguage"
+            ><span v-html="highlightedSolution"></span></pre>
+          </div>
         </v-expansion-panel-content>
       </v-expansion-panel>
     </v-card>
@@ -47,7 +47,8 @@ export default class SubmissionType extends Vue {
   }) description!: string
   @Prop({
     type: String,
-    required: true
+    required: false,
+    default: ''
   }) solution!: string
   @Prop({
     type: Number,
@@ -80,12 +81,14 @@ export default class SubmissionType extends Vue {
       {
         title: 'Description',
         text: this.description
-      },
-      {
-        title: 'Solution',
-        text: this.solution
       }
     ]
+    if (this.solution) {
+      items.push({
+        title: 'Solution',
+        text: this.solution
+      })
+    }
     if (this.reverse) {
       return items.reverse()
     } else {
diff --git a/frontend/src/components/student/ExamInformation.vue b/frontend/src/components/student/ExamInformation.vue
index ac0e0148..0c223f43 100644
--- a/frontend/src/components/student/ExamInformation.vue
+++ b/frontend/src/components/student/ExamInformation.vue
@@ -1,6 +1,9 @@
 <template>
-  <table class="table table-info rounded">
-    <tbody>
+  <table class="table table-info rounded exam-table">
+    <tbody v-if="!exam">
+      No exam information present
+    </tbody>
+    <tbody v-else>
       <tr>
         <th>Module</th>
         <td>{{ exam.moduleReference }}</td>
@@ -29,3 +32,9 @@ export default class ExamInformation extends Vue {
   @Prop(Object) exam!: Exam
 }
 </script>
+
+<style>
+.exam-table {
+  width: 100%
+}
+</style>
diff --git a/frontend/src/components/student/SubmissionList.vue b/frontend/src/components/student/SubmissionList.vue
index b7dd7052..d06b481e 100644
--- a/frontend/src/components/student/SubmissionList.vue
+++ b/frontend/src/components/student/SubmissionList.vue
@@ -4,7 +4,7 @@
       hide-actions
       :headers="headers"
       :items="submissions"
-      item-key="type"
+      item-key="type.pk"
     >
       <template slot="items" slot-scope="props">
         <td>{{ props.item.type.name }}</td>
@@ -32,7 +32,7 @@ export default {
         {
           text: 'Task',
           align: 'left',
-          value: 'type',
+          value: 'type.name',
           sortable: false
         },
         {
diff --git a/frontend/src/components/student_list/StudentListMenu.vue b/frontend/src/components/student_list/StudentListMenu.vue
index 616c7430..53a5f0c4 100644
--- a/frontend/src/components/student_list/StudentListMenu.vue
+++ b/frontend/src/components/student_list/StudentListMenu.vue
@@ -14,7 +14,7 @@
 <script>
 import {activateAllStudentAccess,
   deactivateAllStudentAccess} from '@/api'
-import { actions } from '@/store/actions';
+import { actions } from '@/store/actions'
 
 export default {
   name: 'student-list-menu',
diff --git a/frontend/src/models.ts b/frontend/src/models.ts
index ddf2d432..ce4b7e97 100644
--- a/frontend/src/models.ts
+++ b/frontend/src/models.ts
@@ -503,7 +503,7 @@ export interface SubmissionType {
      * @type {string}
      * @memberof SubmissionType
      */
-    solution: string
+    solution?: string
     /**
      *
      * @type {string}
diff --git a/frontend/src/pages/base/TutorReviewerBaseLayout.vue b/frontend/src/pages/base/TutorReviewerBaseLayout.vue
index e59264d0..898ebe36 100644
--- a/frontend/src/pages/base/TutorReviewerBaseLayout.vue
+++ b/frontend/src/pages/base/TutorReviewerBaseLayout.vue
@@ -45,7 +45,7 @@ export default {
           route: '/home'
         },
         {
-          name: 'Feedback',
+          name: 'Feedback History',
           icon: 'feedback',
           route: '/feedback'
         }
diff --git a/frontend/src/pages/student/StudentLayout.vue b/frontend/src/pages/student/StudentLayout.vue
index 6c8ff0d4..079851e5 100644
--- a/frontend/src/pages/student/StudentLayout.vue
+++ b/frontend/src/pages/student/StudentLayout.vue
@@ -20,11 +20,11 @@
 
       <v-divider></v-divider>
 
-            <exam-information
-              :exam="exam"
-              v-if="!mini"
-              class="elevation-1 exam-info ma-1"
-            />
+      <exam-information
+        :exam="exam"
+        v-if="!mini"
+        class="elevation-1 exam-info ma-1"
+      />
       <v-list-tile exact v-for="item in submissionNavItems" :key="item.route" :to="item.route">
         <v-list-tile-action>
           <v-icon v-if="!visited[item.id]">assignment</v-icon>
@@ -60,10 +60,10 @@ export default {
     }
   },
   computed: {
-    moduleReference () { return StudentPage.state.exam.moduleReference },
     submissions () { return StudentPage.state.submissionsForList },
     exam () { return StudentPage.state.exam },
     visited () { return StudentPage.state.visited },
+    moduleReference () { return this.exam ? this.exam.moduleReference : 'No exam information' },
 
     mini () { return UI.state.mini },
 
diff --git a/frontend/src/pages/student/StudentPage.vue b/frontend/src/pages/student/StudentPage.vue
index 13729b0a..d9d2c31f 100644
--- a/frontend/src/pages/student/StudentPage.vue
+++ b/frontend/src/pages/student/StudentPage.vue
@@ -12,17 +12,13 @@
 </template>
 
 <script>
-import {mapState} from 'vuex'
-import StudentLayout from './StudentLayout.vue'
 import SubmissionList from '@/components/student/SubmissionList.vue'
-import ExamInformation from '@/components/student/ExamInformation.vue'
 import { StudentPage } from '@/store/modules/student-page'
 
 export default {
   components: {
-    ExamInformation,
-    SubmissionList,
-    StudentLayout},
+    SubmissionList
+  },
   name: 'student-page',
   created: function () {
     if (!this.loaded) {
@@ -33,7 +29,6 @@ export default {
   },
   computed: {
     studentName () { return StudentPage.state.studentName },
-    exam () { return StudentPage.state.exam },
     submissions () { return StudentPage.state.submissionsForList },
     loaded () { return StudentPage.state.loaded }
   }
diff --git a/frontend/src/pages/student/StudentSubmissionPage.vue b/frontend/src/pages/student/StudentSubmissionPage.vue
index a15579db..d921bb79 100644
--- a/frontend/src/pages/student/StudentSubmissionPage.vue
+++ b/frontend/src/pages/student/StudentSubmissionPage.vue
@@ -88,8 +88,7 @@ export default {
   methods: {
     onRouteMountOrUpdate (routeId) {
       StudentPage.SET_VISITED({ index: routeId, visited: true })
-      // TODO this seems fishy and there probably is the student page bug in here
-      SubmissionNotes.SET_SUBMISSION(this.$store.state.studentPage.submissionData[this.id])
+      SubmissionNotes.SET_SUBMISSION(StudentPage.state.submissionData[routeId])
     }
   },
   mounted () {
diff --git a/frontend/src/store/actions.ts b/frontend/src/store/actions.ts
index f70fa39f..3d5982c3 100644
--- a/frontend/src/store/actions.ts
+++ b/frontend/src/store/actions.ts
@@ -10,19 +10,19 @@ import { RootState } from '@/store/store'
 import { FeedbackTable } from '@/store/modules/feedback_list/feedback-table'
 import { Subscriptions } from '@/store/modules/subscriptions'
 
-async function getExamTypes(context: BareActionContext<RootState, RootState>) {
-  const examTypes = await api.fetchExamTypes({})
+async function getExamTypes (context: BareActionContext<RootState, RootState>) {
+  const examTypes = await api.fetchExamTypes()
   mut.SET_EXAM_TYPES(examTypes)
 }
-async function updateSubmissionTypes(
-  context: BareActionContext<RootState, RootState>,
+async function updateSubmissionTypes (
+  context: BareActionContext<RootState, RootState>
 ) {
   const submissionTypes = await api.fetchSubmissionTypes()
   submissionTypes.forEach(type => {
     mut.UPDATE_SUBMISSION_TYPE(type)
   })
 }
-async function getStudents(
+async function getStudents (
   context: BareActionContext<RootState, RootState>,
   opt: { studentPks: Array<string>} = {
     studentPks: []
@@ -42,11 +42,11 @@ async function getStudents(
     return students
   }
 }
-async function getTutors() {
+async function getTutors () {
   const tutors = await api.fetchAllTutors()
   mut.SET_TUTORS(tutors)
 }
-async function getFeedback(
+async function getFeedback (
   context: BareActionContext<RootState, RootState>,
   fetchFeedbackArg: { ofSubmission: string }
 ) {
@@ -54,38 +54,34 @@ async function getFeedback(
   mut.SET_FEEDBACK(feedback)
   return feedback
 }
-async function getSubmissionFeedbackTest(
+async function getSubmissionFeedbackTest (
   context: BareActionContext<RootState, RootState>,
   submissionPkObj: { pk: string }
 ) {
   const submission = await api.fetchSubmissionFeedbackTests(submissionPkObj)
   mut.SET_SUBMISSION(submission)
 }
-async function getStatistics() {
+async function getStatistics () {
   const statistics = await api.fetchStatistics()
   mut.SET_STATISTICS(statistics)
 }
-function logout(
+function logout (
   context: BareActionContext<RootState, RootState>,
-  message = ""
+  message = ''
 ) {
-  // logout actually receives a normal ActionContext, but for some reason vuex-typex mandates a BareActionContext
-  // TODO there has to be a better way
-  const { commit, getters, state } = <ActionContext<RootState, RootState>>(
-    context
-  )
   if (Authentication.isStudent) {
     // change active to false when user logs out
     // TODO this should belong in auth module
     api.changeActiveForUser(Authentication.state.user.pk, false)
   }
+  router.push({ name: 'login' })
+  // there should be a better way to solve the issue of resetting the once() function used in subscription module
   mut.RESET_STATE()
   FeedbackTable.RESET_STATE()
   Authentication.RESET_STATE()
   Subscriptions.RESET_STATE()
   SubmissionNotes.RESET_STATE()
   Authentication.SET_MESSAGE(message)
-  router.push({ name: "login" })
   router.go(0)
 }
 
-- 
GitLab