ソースを参照

:sparkles: added survey plugin which grabs all response questions | added profile plug which grabs profiles and responses by user

master
j 5年前
コミット
6b237589bb

+ 13
- 3
backend/lib/index.js ファイルの表示

@@ -1,5 +1,7 @@
1 1
 const UserPlugin = require('./plugins/user')
2 2
 const MembershipPlugin = require('./plugins/membership')
3
+const SurveyPlugin = require('./plugins/survey')
4
+const ProfilePlugin = require('./plugins/profile')
3 5
 const TestPlugin = require('./plugins/example')
4 6
 
5 7
 /**
@@ -23,15 +25,23 @@ exports.plugin = {
23 25
      */
24 26
     register: async (server, options) => {
25 27
         await server.register(TestPlugin, {
26
-            routes: { prefix: `/example` },
28
+            routes: { prefix: '/example' },
27 29
         })
28 30
 
29 31
         await server.register(UserPlugin, {
30
-            routes: { prefix: `/user` },
32
+            routes: { prefix: '/user' },
31 33
         })
32 34
 
33 35
         await server.register(MembershipPlugin, {
34
-            routes: { prefix: `/membership` },
36
+            routes: { prefix: '/membership' },
37
+        })
38
+
39
+        await server.register(SurveyPlugin, {
40
+            routes: { prefix: '/survey' },
41
+        })
42
+
43
+        await server.register(ProfilePlugin, {
44
+            routes: { prefix: '/profile' },
35 45
         })
36 46
     },
37 47
 }

+ 29
- 0
backend/lib/plugins/profile.js ファイルの表示

@@ -0,0 +1,29 @@
1
+const Objection = require('objection')
2
+const Schmervice = require('@hapipal/schmervice')
3
+
4
+const ProfileModel = require('../models/profile')
5
+const ResponseModel = require('../models/response')
6
+
7
+const ProfileService = require('../services/profile')
8
+
9
+const ProfileProfilesRoute = require('../routes/profile/profiles')
10
+
11
+module.exports = {
12
+    name: 'profile-plugin',
13
+    version: '1.0.0',
14
+    register: async (server, options) => {
15
+        await server.registerModel(ProfileModel)
16
+        await server.registerModel(ResponseModel)
17
+
18
+        // Bind to global context
19
+        // So we can use Objection transactions
20
+        server.bind({
21
+            transaction: fn => Objection.transaction(server.knex(), fn),
22
+        })
23
+
24
+        await server.register(Schmervice)
25
+        server.registerService(ProfileService)
26
+
27
+        await server.route(ProfileProfilesRoute)
28
+    },
29
+}

+ 27
- 0
backend/lib/plugins/survey.js ファイルの表示

@@ -0,0 +1,27 @@
1
+const Objection = require('objection')
2
+const Schmervice = require('@hapipal/schmervice')
3
+
4
+const ReponseKeyModel = require('../models/response-key')
5
+
6
+const ResponseService = require('../services/response')
7
+
8
+const ResponseQuestionsRoute = require('../routes/survey/questions')
9
+
10
+module.exports = {
11
+    name: 'survey-plugin',
12
+    version: '1.0.0',
13
+    register: async (server, options) => {
14
+        await server.registerModel(ReponseKeyModel)
15
+
16
+        // Bind to global context
17
+        // So we can use Objection transactions
18
+        server.bind({
19
+            transaction: fn => Objection.transaction(server.knex(), fn),
20
+        })
21
+
22
+        await server.register(Schmervice)
23
+        server.registerService(ResponseService)
24
+
25
+        await server.route(ResponseQuestionsRoute)
26
+    },
27
+}

+ 85
- 0
backend/lib/routes/profile/profiles.js ファイルの表示

@@ -0,0 +1,85 @@
1
+'use strict'
2
+
3
+const Joi = require('joi')
4
+
5
+const pluginConfig = {
6
+    handlerType: 'profile',
7
+    docs: {
8
+        description: 'profiles',
9
+        notes: 'A list of profiles associated with this user',
10
+    },
11
+}
12
+
13
+const validators = {
14
+    /** Validate the header (cookie check) */
15
+    // headers: true,
16
+
17
+    /** Validate the route params (/active/{thing}) */
18
+    params: Joi.object({ user_id: Joi.number() }),
19
+
20
+    /** Validate the route query (/active/{thing}?limit=10&offset=10) */
21
+    // query: true,
22
+    /** Validate the incoming payload (POST method) */
23
+    // payload: true,
24
+}
25
+
26
+const responseSchemas = {
27
+    profilesList: Joi.object({
28
+        profile_id: Joi.number().required(),
29
+        user_id: Joi.number().required(),
30
+        responses: Joi.array().items(
31
+            Joi.object({
32
+                response_id: Joi.number().required(),
33
+                profile_id: Joi.number().required(),
34
+                response_key_id: Joi.number().required(),
35
+                val: Joi.string().required(),
36
+            }),
37
+        ),
38
+        response_keys: Joi.array(),
39
+    }),
40
+}
41
+
42
+module.exports = {
43
+    method: 'GET',
44
+    path: '/{user_id}',
45
+    options: {
46
+        ...pluginConfig.docs,
47
+        tags: ['api'],
48
+        /** Protect this route with authentication? */
49
+        auth: false,
50
+
51
+        handler: async function (request, h) {
52
+            const { profileService } = request.services()
53
+            const userId = request.params.user_id
54
+            const profiles = await profileService.getCompleteProfilesFor(userId)
55
+            try {
56
+                return {
57
+                    ok: true,
58
+                    handler: pluginConfig.handlerType,
59
+                    data: profiles,
60
+                }
61
+            } catch (err) {
62
+                return {
63
+                    ok: false,
64
+                    handler: pluginConfig.handlerType,
65
+                    data: { error: `${err}` },
66
+                }
67
+            }
68
+        },
69
+
70
+        /** Validate based on validators object */
71
+        validate: {
72
+            ...validators,
73
+            failAction: 'log',
74
+        },
75
+
76
+        /** Validate the server response */
77
+        response: {
78
+            schema: Joi.object({
79
+                ok: Joi.bool(),
80
+                handler: Joi.string(),
81
+                data: Joi.array().items(responseSchemas.profilesList),
82
+            }),
83
+        },
84
+    },
85
+}

+ 0
- 0
backend/lib/routes/response/respond.js ファイルの表示


+ 72
- 0
backend/lib/routes/survey/questions.js ファイルの表示

@@ -0,0 +1,72 @@
1
+'use strict'
2
+
3
+const Joi = require('joi')
4
+
5
+const pluginConfig = {
6
+    handlerType: 'survey',
7
+    docs: {
8
+        description: 'Get survey questions',
9
+        notes: 'Returns a list of all possible survey questions in the form of response_keys',
10
+    },
11
+}
12
+
13
+/** Validator functions by request method */
14
+const validators = {
15
+    /** Validate the header (cookie check) */
16
+    // headers: true,
17
+    /** Validate the route params (/active/{thing}) */
18
+    // params: true,
19
+    /** Validate the route query (/active/{thing}?limit=10&offset=10) */
20
+    // query: true,
21
+    /** Validate the incoming payload (POST method) */
22
+    // payload: true,
23
+}
24
+const responseSchemas = {
25
+    responseKeysList: Joi.object({
26
+        response_key_id: Joi.number().required(),
27
+        profile_id: Joi.number().required(),
28
+        val: Joi.string().required(),
29
+    }),
30
+}
31
+
32
+module.exports = {
33
+    method: 'GET',
34
+    path: '/questions',
35
+    options: {
36
+        ...pluginConfig.docs,
37
+        tags: ['api'],
38
+        /** Protect this route with authentication? */
39
+        auth: false,
40
+
41
+        handler: async function (request, h) {
42
+            const { responseService } = request.services()
43
+            const responseKeys = await responseService.getResponseKeys()
44
+            try {
45
+                return {
46
+                    ok: true,
47
+                    handler: pluginConfig.handlerType,
48
+                    data: responseKeys,
49
+                }
50
+            } catch (err) {
51
+                return {
52
+                    ok: false,
53
+                    handler: pluginConfig.handlerType,
54
+                    data: { error: err },
55
+                }
56
+            }
57
+        },
58
+
59
+        /** Validate based on validators object */
60
+        validate: { ...validators, failAction: 'log' },
61
+
62
+        /** Validate the server response */
63
+        response: {
64
+            schema: Joi.object({
65
+                ok: Joi.bool(),
66
+                handler: Joi.string(),
67
+                data: Joi.array().items(responseSchemas.responseKeysList),
68
+            }),
69
+            failAction: 'log',
70
+        },
71
+    },
72
+}

+ 71
- 0
backend/lib/routes/survey/responses.js ファイルの表示

@@ -0,0 +1,71 @@
1
+'use strict'
2
+
3
+const Joi = require('joi')
4
+
5
+const pluginConfig = {
6
+    handlerType: 'survey',
7
+    docs: {
8
+        description: 'Get responses to questions',
9
+        notes: 'Returns a list of all survey responses for a user',
10
+    },
11
+}
12
+
13
+/** Validator functions by request method */
14
+const validators = {
15
+    /** Validate the header (cookie check) */
16
+    // headers: true,
17
+    /** Validate the route params (/active/{thing}) */
18
+    params: Joi.object({ user_id: Joi.number() }),
19
+    /** Validate the route query (/active/{thing}?limit=10&offset=10) */
20
+    // query: true,
21
+    /** Validate the incoming payload (POST method) */
22
+    // payload: true,
23
+}
24
+const responseSchemas = {
25
+    responseKeysList: Joi.object({
26
+        response_key_id: Joi.number().required(),
27
+        profile_id: Joi.number().required(),
28
+    }),
29
+}
30
+
31
+module.exports = {
32
+    method: 'GET',
33
+    path: '/questions',
34
+    options: {
35
+        ...pluginConfig.docs,
36
+        tags: ['api'],
37
+        /** Protect this route with authentication? */
38
+        auth: false,
39
+
40
+        handler: async function (request, h) {
41
+            const { responseService } = request.services()
42
+            const responseKeys = await responseService.getResponseKeys()
43
+            try {
44
+                return {
45
+                    ok: true,
46
+                    handler: pluginConfig.handlerType,
47
+                    data: responseKeys,
48
+                }
49
+            } catch (err) {
50
+                return {
51
+                    ok: false,
52
+                    handler: pluginConfig.handlerType,
53
+                    data: { error: err },
54
+                }
55
+            }
56
+        },
57
+
58
+        /** Validate based on validators object */
59
+        validate: { ...validators, failAction: 'log' },
60
+
61
+        /** Validate the server response */
62
+        response: {
63
+            schema: Joi.object({
64
+                ok: Joi.bool(),
65
+                handler: Joi.string(),
66
+                data: Joi.array().items(responseSchemas.responseKeysList),
67
+            }),
68
+            failAction: 'log',
69
+        },
70
+    },
71
+}

+ 79
- 0
backend/lib/services/profile.js ファイルの表示

@@ -0,0 +1,79 @@
1
+const Schmervice = require('@hapipal/schmervice')
2
+
3
+module.exports = class ProfileService extends Schmervice.Service {
4
+    constructor(...args) {
5
+        super(...args)
6
+    }
7
+
8
+    /**
9
+     * Internal method to get list of profile_ids for this user
10
+     * @param {number} userId
11
+     * @returns {Array} List of all profile_ids for user
12
+     */
13
+    async _getProfileIdsForUserId(userId) {
14
+        const { Profile } = this.server.models()
15
+
16
+        /** Grab every Profile associated with this id */
17
+        const allProfiles = await Profile.query().where('user_id', userId)
18
+
19
+        /** Copy a list of the just the Profiles */
20
+        const profileIdsToGrab = allProfiles.map(profile => profile.profile_id)
21
+
22
+        /** Uncomment to dedupe the list just in case */
23
+        return [...new Set(profileIdsToGrab)]
24
+    }
25
+
26
+    async getCompleteProfilesFor(userId) {
27
+        const { Profile, Response } = this.server.models()
28
+
29
+        const dedupedProfiles = await this._getProfileIdsForUserId(userId)
30
+
31
+        const responses = await Response.query().whereIn(
32
+            'profile_id',
33
+            dedupedProfiles,
34
+        )
35
+        const profiles = await Profile.query().whereIn(
36
+            'profile_id',
37
+            dedupedProfiles,
38
+        )
39
+
40
+        //** Get responses asociated with each profile_id */
41
+        return profiles.map(profile => {
42
+            if (!profile.responses) profile.responses = []
43
+            profile.response_keys = []
44
+            responses.forEach(response => {
45
+                if (response.profile_id !== profile.profile_id) return
46
+                profile.response_keys.push(response.response_key_id)
47
+                profile.responses.push(response)
48
+            })
49
+
50
+            return profile
51
+        })
52
+    }
53
+
54
+    /**
55
+     * Save responses in a profile
56
+     * @param {number} userId
57
+     * @param {Array} responses
58
+     * @returns
59
+     */
60
+    async saveProfile(userId, responses, txn) {
61
+        console.warn(userId, responses, txn)
62
+    }
63
+    /**
64
+     * Delete a profile
65
+     * @param {number} userId
66
+     * @param {number} profileId
67
+     * @returns
68
+     */
69
+    async deleteProfile(userId, profileId) {
70
+        const { Profile } = this.server.models()
71
+
72
+        const dedupedGroupings = await this._getProfileIdsForUserId(userId)
73
+
74
+        /** Do NOTHING if NOT in Grouping */
75
+        if (!dedupedGroupings.includes(profileId)) return
76
+
77
+        return await Profile.query().delete().where('profile_id', profileId)
78
+    }
79
+}

+ 21
- 0
backend/lib/services/response.js ファイルの表示

@@ -0,0 +1,21 @@
1
+const Schmervice = require('@hapipal/schmervice')
2
+
3
+module.exports = class ResponseService extends Schmervice.Service {
4
+    constructor(...args) {
5
+        super(...args)
6
+    }
7
+
8
+    /**
9
+     * Internal method to get list of possible response_keys (questions)
10
+     * @returns {Array} List of all response_keys
11
+     */
12
+    async getResponseKeys() {
13
+        const { ResponseKey } = this.server.models()
14
+
15
+        /** Grab every ResponseKey */
16
+        const allResponseKeys = await ResponseKey.query()
17
+
18
+        /** Uncomment to dedupe the list just in case */
19
+        return [...new Set(allResponseKeys)]
20
+    }
21
+}

読み込み中…
キャンセル
保存