Parcourir la source

Merge branch 'feature/link-generator-select' into develop

rigwild il y a 4 ans
Parent
commit
e7e7533020

+ 17 - 4
server/routes/dataCollect.js

@@ -20,10 +20,13 @@ const router = express.Router()
  * @apiDescription Collect user's data
  *
  * @apiParam {String} uuid The unique user identifier
+ * @apiParam {String} userId The user ID
+ * @apiParam {String} experimentId The experiment ID
+ * @apiParam {String} uuid The unique user identifier
  * @apiParam {Object} screen Screen data, `window.screen` @see https://developer.mozilla.org/en-US/docs/Web/API/Screen
  *
  * @apiExample Usage example
- * curl -i -L -H "Content-Type: application/json" -X POST "http://diran.univ-littoral.fr/api/dataCollect" -d {"uuid":"test","screen":{"width":1920,"height":1024}}
+ * curl -i -L -H "Content-Type: application/json" -X POST "http://diran.univ-littoral.fr/api/dataCollect" -d {"uuid":"test","userId":"rigwild","experimentId":"expe-test","screen":{"width":1920,"height":1024}}
  *
  * @apiSuccessExample {string} Success response example
  * HTTP/1.1 200 OK /api/dataCollect
@@ -33,7 +36,7 @@ const router = express.Router()
  * @apiErrorExample {json} Missing parameter
  * HTTP/1.1 400 Bad Request
  * {
- *   "message": "Missing parameter(s). Required parameters : uuid, screen."
+ *   "message": "Missing parameter(s). Required parameters : uuid, userId, experimentId, screen."
  * }
  *
  * @apiError (Error 4xx) 400_[2] Invalid query parameter
@@ -43,6 +46,8 @@ const router = express.Router()
  *   "message": "Invalid body parameter(s).",
  *   "data": [
  *     "\"uuid\" must be a string.",
+ *     "\"userId\" must be a string.",
+ *     "\"experimentId\" must be a string.",
  *     "\"screen\" must be a valid object."
  *   ]
  * }
@@ -52,13 +57,19 @@ const router = express.Router()
 router.post('/', asyncMiddleware(async (req, res) => {
   // Check the request contains all the required body parameters
   const b = req.body
-  checkRequiredParameters(['uuid', 'screen'], b)
+  checkRequiredParameters(['uuid', 'screen', 'userId', 'experimentId'], b)
 
   let errorList = []
 
   if (typeof b.uuid !== 'string')
     errorList.push('"uuid" must be a string.')
 
+  if (b.userId && typeof b.userId !== 'string')
+    errorList.push('"userId" must be a string.')
+
+  if (b.experimentId && typeof b.experimentId !== 'string')
+    errorList.push('"experimentId" must be a string.')
+
   if (typeof b.screen !== 'object' || Object.keys(b.screen).length > 30)
     errorList.push('"screen" must be a valid object.')
 
@@ -76,7 +87,9 @@ router.post('/', asyncMiddleware(async (req, res) => {
       screen: b.screen,
       userAgent,
       ip: req.ip
-    }
+    },
+    userid: b.userId || null,
+    experimentId: b.experimentId || null
   }
 
   if (!TEST_MODE) await DataController.add(data)

+ 18 - 1
src/App.vue

@@ -24,7 +24,16 @@
             </v-list-tile-content>
           </v-list-tile>
 
-          <v-list-tile @click="loadScenes">
+          <v-list-tile to="/linkGenerator" exact>
+            <v-list-tile-action>
+              <v-icon>share</v-icon>
+            </v-list-tile-action>
+            <v-list-tile-content>
+              <v-list-tile-title>Link generator</v-list-tile-title>
+            </v-list-tile-content>
+          </v-list-tile>
+
+          <v-list-tile @click="loadScenesHard">
             <v-list-tile-action>
               <v-icon>refresh</v-icon>
             </v-list-tile-action>
@@ -89,6 +98,9 @@ export default {
     },
     isHostConfigured(isConfigured) {
       if (isConfigured) this.APP_LOADER()
+    },
+    areScenesLoaded(areLoaded) {
+      if (areLoaded) this.APP_LOADER()
     }
   },
   mounted() {
@@ -108,6 +120,11 @@ export default {
       return this.load(this.loadScenesList, 'Loading scenes list...')
     },
 
+    async loadScenesHard() {
+      await this.loadScenes()
+      this.$router.go()
+    },
+
     async load(fn, loadingMessage) {
       try {
         this.loadingMessage = loadingMessage

+ 3 - 3
src/components/ResetAppButton.vue

@@ -19,7 +19,6 @@
 
         <v-divider />
 
-
         <v-card-actions>
           <v-btn color="secondary" flat @click="showDialog = false">Cancel</v-btn>
           <v-spacer />
@@ -75,7 +74,8 @@ export default {
       items: [
         { text: 'GDPR consent', value: 'gdprConsent' },
         { text: 'Host configuration and User/Experiment ID', value: 'hostConfig' },
-        { text: 'Progression', value: 'progression' }
+        { text: 'Progression', value: 'progression' },
+        { text: 'Scenes list', value: 'scenesList' }
       ]
     }
   },
@@ -93,6 +93,7 @@ export default {
     }
   },
   methods: {
+    ...mapActions(['resetApp']),
     toggle() {
       this.$nextTick(() => {
         if (this.selectAll) {
@@ -104,7 +105,6 @@ export default {
       })
     },
 
-    ...mapActions(['resetApp']),
     reset() {
       const toReset = this.selectedItems.reduce((acc, x) => {
         acc[x.value] = true

+ 3 - 3
src/mixins/ExperimentBaseAreSameImages.vue

@@ -81,12 +81,12 @@ export default {
         }, additionalData || {})
         this.sendMessage({ msgId: experimentMsgId.DATA, msg: obj })
 
+        // Experiment end
+        if (this.testCount > this.maxTestCount) return this.finishExperiment()
+
         const { image1, image2 } = await getTestFn()
         this.image1 = image1
         this.image2 = image2
-
-        // Experiment end
-        if (this.testCount > this.maxTestCount) return this.finishExperiment()
       }
       catch (err) {
         console.error('Failed to load new test', err)

+ 8 - 2
src/store/actions.js

@@ -13,7 +13,11 @@ export default {
     if (!state.uuid) commit('setAppUniqueId')
   },
 
-  resetApp({ commit }, { gdprConsent = false, hostConfig = false, progression = false }) {
+  async resetApp({ dispatch, commit }, { gdprConsent = false, hostConfig = false, progression = false, scenesList = false }) {
+    if (!gdprConsent && !hostConfig && scenesList) {
+      await dispatch('loadScenesList')
+      router.go()
+    }
     commit('resetApp', { gdprConsent, hostConfig, progression })
   },
 
@@ -42,7 +46,7 @@ export default {
       })
   },
 
-  setUserExperimentId({ commit }, { userId, experimentId }) {
+  setUserExperimentId({ commit }, { userId = null, experimentId = null }) {
     commit('setUserExperimentId', { userId, experimentId })
   },
 
@@ -57,6 +61,8 @@ export default {
       },
       body: JSON.stringify({
         uuid: state.uuid,
+        userId: state.userId,
+        experimentId: state.experimentId,
         screen
       })
     })

+ 5 - 5
src/store/mutations.js

@@ -42,11 +42,11 @@ export default {
     const defaultStateObj = defaultState()
     if (gdprConsent) {
       state.gdprConsent = false
-      delete state.userId
-      delete state.experimentId
-      delete state.hostConfig
-      delete state.progression
-      delete state.scenesList
+      state.hostConfig = defaultStateObj.hostConfig
+      state.userId = defaultStateObj.userId
+      state.experimentId = defaultStateObj.experimentId
+      state.progression = defaultStateObj.progression
+      state.scenesList = defaultStateObj.scenesList
       return
     }
 

+ 2 - 2
src/views/Experiments/IsImageCorrect.vue

@@ -147,10 +147,10 @@ export default {
         }
         this.sendMessage({ msgId: experimentMsgId.DATA, msg: experimentalData })
 
-        await this.getReconstructedImage()
-
         // Experiment end
         if (this.testCount > this.maxTestCount) return this.finishExperiment()
+
+        await this.getReconstructedImage()
       }
       catch (err) {
         console.error('Failed to load new test', err)

+ 3 - 2
src/views/Experiments/IsImageCorrectOneExtract.vue

@@ -127,6 +127,7 @@ export default {
       maxExtracts.extracts[position] = randomExtracts.extracts[position]
       this.reconstructedImage = maxExtracts.extracts
     },
+
     // get next reconstructed image
     async nextReconstructedImage(correct) {
       this.loadingMessage = 'Loading new test...'
@@ -146,10 +147,10 @@ export default {
         }
         this.sendMessage({ msgId: experimentMsgId.DATA, msg: experimentalData })
 
-        await this.getReconstructedImage()
-
         // Experiment end
         if (this.testCount > this.maxTestCount) return this.finishExperiment()
+
+        await this.getReconstructedImage()
       }
       catch (err) {
         console.error('Failed to load new test', err)

+ 2 - 2
src/views/Experiments/PercentQualityRandom.vue

@@ -131,10 +131,10 @@ export default {
         }
         this.sendMessage({ msgId: experimentMsgId.DATA, msg: experimentalData })
 
-        await this.getTest()
-
         // Experiment end
         if (this.testCount > this.maxTestCount) return this.finishExperiment()
+
+        await this.getTest()
       }
       catch (err) {
         console.error('Failed to load new test', err)

+ 4 - 4
src/views/HostConfig.vue

@@ -99,9 +99,9 @@ export default {
   data() {
     return {
       config: {
-        ssl: false,
+        ssl: true,
         host: 'diran.univ-littoral.fr',
-        port: '80'
+        port: '443'
       },
 
       id: {
@@ -135,8 +135,8 @@ export default {
     ...mapActions(['setHostConfig', 'setUserExperimentId']),
     reset() {
       this.config.ssl = true
-      this.config.host = ''
-      this.config.port = null
+      this.config.host = 'diran.univ-littoral.fr'
+      this.config.port = 443
       this.id.user = null
       this.id.hasUserId = false
       this.id.experiment = null

+ 54 - 20
src/views/LinkGenerator.vue

@@ -38,7 +38,7 @@
 
                 <h2>User ID and experiment ID</h2>
                 <v-layout row wrap>
-                  <v-flex xs5>
+                  <v-flex xs4>
                     <v-checkbox
                       v-model="form.userId.activated"
                       color="primary"
@@ -46,7 +46,7 @@
                     />
                   </v-flex>
                   <v-spacer />
-                  <v-flex xs6>
+                  <v-flex xs8>
                     <v-text-field
                       v-model="form.userId.value"
                       label="User ID"
@@ -57,7 +57,7 @@
                 </v-layout>
 
                 <v-layout row wrap>
-                  <v-flex xs5>
+                  <v-flex xs4>
                     <v-checkbox
                       v-model="form.experimentId.activated"
                       color="primary"
@@ -65,7 +65,7 @@
                     />
                   </v-flex>
                   <v-spacer />
-                  <v-flex xs6>
+                  <v-flex xs8>
                     <v-text-field
                       v-model="form.experimentId.value"
                       label="Experiment ID"
@@ -78,38 +78,43 @@
 
                 <h2>Experiment name and scene name</h2>
                 <v-layout row wrap>
-                  <v-flex xs5>
+                  <v-flex xs4>
                     <v-checkbox
                       v-model="form.experimentName.activated"
                       color="primary"
                       label="Experiment name"
+                      @click="form.sceneName.activated = false"
                     />
                   </v-flex>
-                  <v-spacer />
-                  <v-flex xs6>
-                    <v-text-field
+                  <v-flex xs8>
+                    <v-select
                       v-model="form.experimentName.value"
+                      :items="experimentsSelectItems"
+                      item-text="text"
+                      item-value="value"
                       label="Experiment name"
-                      type="text"
                       :disabled="!form.experimentName.activated"
                     />
                   </v-flex>
                 </v-layout>
 
                 <v-layout row wrap>
-                  <v-flex xs5>
+                  <v-flex xs4>
                     <v-checkbox
                       v-model="form.sceneName.activated"
                       color="primary"
                       label="Scene name"
+                      :disabled="!form.experimentName.activated || form.experimentName.value === ''"
                     />
                   </v-flex>
                   <v-spacer />
-                  <v-flex xs6>
-                    <v-text-field
+                  <v-flex xs8>
+                    <v-select
                       v-model="form.sceneName.value"
+                      :items="scenesSelectItems"
+                      item-text="text"
+                      item-value="value"
                       label="Scene name"
-                      type="text"
                       :disabled="!form.sceneName.activated"
                     />
                   </v-flex>
@@ -123,7 +128,7 @@
                     :value="linkOutput"
                     label="Your generated link"
                     type="text"
-                    disabled
+                    readonly
                   />
 
                   Data in the generated link:
@@ -143,6 +148,9 @@
 </template>
 
 <script>
+import Experiments from '@/router/experiments'
+import { getExperimentSceneList } from '@/config.utils'
+
 export default {
   name: 'LinkGenerator',
   components: {
@@ -150,9 +158,9 @@ export default {
   data() {
     return {
       form: {
-        webAppUrl: 'http://diran.univ-littoral.fr',
+        webAppUrl: 'https://diran.univ-littoral.fr',
         server: {
-          ssl: false,
+          ssl: true,
           host: 'diran.univ-littoral.fr',
           port: '80'
         },
@@ -178,12 +186,38 @@ export default {
         }
       },
 
+      experimentsSelectItems: null,
+      scenesSelectItems: null,
+
       linkOutput: null,
       dataOutput: null,
       alertMessage: null
     }
   },
 
+  watch: {
+    'form.experimentName.activated'(newValue) {
+      // Reset available scenes if experiment changed
+      if (!newValue) this.scenesSelectItems = null
+    },
+    'form.experimentName.value'(newValue) {
+      // Reset available scenes if experiment changed
+      if (newValue !== '') this.scenesSelectItems = getExperimentSceneList(this.form.experimentName.value)
+    },
+    'form.sceneName.activated'(newValue) {
+      // Load available scenes when sceneName is activated
+      if (newValue) this.scenesSelectItems = getExperimentSceneList(this.form.experimentName.value)
+      else this.scenesSelectItems = null
+    }
+  },
+
+  mounted() {
+    this.experimentsSelectItems = Experiments.map(expe => ({
+      text: `${expe.name} - ${expe.meta.fullName}`,
+      value: expe.name
+    }))
+  },
+
   methods: {
     generateLink() {
       this.alertMessage = null
@@ -204,10 +238,10 @@ export default {
           port: this.form.server.port
         }
       }
-      if (this.form.userId.activated && this.form.userId.value !== '')obj.userId = this.form.userId.value
-      if (this.form.experimentId.activated && this.form.experimentId.value !== '')obj.experimentId = this.form.experimentId.value
-      if (this.form.experimentName.activated && this.form.experimentName.value !== '')obj.experimentName = this.form.experimentName.value
-      if (this.form.sceneName.activated && this.form.sceneName.value !== '')obj.sceneName = this.form.sceneName.value
+      if (this.form.userId.activated && this.form.userId.value !== '') obj.userId = this.form.userId.value
+      if (this.form.experimentId.activated && this.form.experimentId.value !== '') obj.experimentId = this.form.experimentId.value
+      if (this.form.experimentName.activated && this.form.experimentName.value !== '') obj.experimentName = this.form.experimentName.value
+      if (this.form.sceneName.activated && this.form.sceneName.value !== '') obj.sceneName = this.form.sceneName.value
 
       // eslint-disable-next-line no-div-regex
       const q = btoa(JSON.stringify(obj)).replace(/=/g, '')

+ 6 - 2
test/server/api/dataCollect.js

@@ -17,24 +17,28 @@ test('POST /dataCollect - No body', async t => {
   t.is(res.status, 400, json(res))
   t.true(res.body.message.includes('Missing parameter'), json(res.body))
   t.true(res.body.message.includes('uuid'), json(res.body))
+  t.true(res.body.message.includes('userId'), json(res.body))
+  t.true(res.body.message.includes('experimentId'), json(res.body))
   t.true(res.body.message.includes('screen'), json(res.body))
 })
 
 test('POST /dataCollect - Invalid body parameters', async t => {
   const res = await request(t.context.server)
     .post(`${apiPrefix}/dataCollect`)
-    .send({ uuid: 42, screen: 'not an object' })
+    .send({ uuid: 42, userId: 42, experimentId: 42, screen: 'not an object' })
 
   t.is(res.status, 400, json(res))
   t.true(res.body.message.includes('Invalid body parameter'), json(res.body))
   t.truthy(res.body.data.find(x => x.includes('"uuid" must be a string.')), json(res.body))
+  t.truthy(res.body.data.find(x => x.includes('"userId" must be a string.')), json(res.body))
+  t.truthy(res.body.data.find(x => x.includes('"experimentId" must be a string.')), json(res.body))
   t.truthy(res.body.data.find(x => x.includes('"screen" must be a valid object.')), json(res.body))
 })
 
 test('POST /dataCollect - Valid body parameters', async t => {
   const res = await request(t.context.server)
     .post(`${apiPrefix}/dataCollect`)
-    .send({ uuid: 'test', screen: { width: 1920, height: 1080 } })
+    .send({ uuid: 'test', userId: 'user-test', experimentId: 'expe-test', screen: { width: 1920, height: 1080 } })
 
   t.is(res.status, 200, json(res))
   t.is(res.body.message, 'OK', json(res.body))