Просмотр исходного кода

:recycle: integrating chat view into pairs and reworking pubnub

tags/0.0.1^2
j 3 лет назад
Родитель
Сommit
81eced6e29

+ 6
- 6
backend/docker-compose.yml Просмотреть файл

@@ -1,16 +1,16 @@
1
-version: "3"
1
+version: '3'
2 2
 
3 3
 services:
4 4
     siimee-db:
5
-        image: mariadb:latest
5
+        image: mariadb:10.7
6 6
         container_name: siimee-dev-mariadb
7 7
         volumes:
8
-          - siimee_db:/var/lib/mysql
8
+            - siimee_db:/var/lib/mysql
9 9
         environment:
10
-          MYSQL_ROOT_PASSWORD: "${DB_ROOT_PASSWORD}"
11
-          MYSQL_DATABASE: "${DB_NAME}"
10
+            MYSQL_ROOT_PASSWORD: '${DB_ROOT_PASSWORD}'
11
+            MYSQL_DATABASE: '${DB_NAME}'
12 12
         ports:
13
-          - "${DB_PORT}:3306"
13
+            - '${DB_PORT}:3306'
14 14
 
15 15
 volumes:
16 16
     siimee_db:

+ 11
- 10
backend/knexfile.js Просмотреть файл

@@ -1,22 +1,23 @@
1
-require('dotenv').config({path: './server/.env'})
2
-// require('dotenv').config()
1
+require('dotenv').config()
3 2
 
4 3
 const local = {
5 4
     host: process.env.DB_HOST,
6 5
     user: process.env.DB_USER,
7 6
     password: process.env.DB_ROOT_PASSWORD,
8 7
     database: process.env.DB_NAME,
9
-    port: process.env.DB_PORT
8
+    port: process.env.DB_PORT,
10 9
 }
11 10
 const pscale = {
12 11
     host: process.env.PSCALE_DB_HOST ? process.env.PSCALE_DB_HOST : '127.0.0.1',
13 12
     user: process.env.PSCALE_DB_USER ? process.env.PSCALE_DB_USER : 'root',
14
-    password: process.env.PSCALE_DB_PASSWORD ? process.env.PSCALE_DB_PASSWORD : '', 
13
+    password: process.env.PSCALE_DB_PASSWORD
14
+        ? process.env.PSCALE_DB_PASSWORD
15
+        : '',
15 16
     database: process.env.PSCALE_DB_NAME,
16
-    port: process.env.PSCALE_DB_PORT ? process.env.PSCALE_DB_PORT : 3306
17
+    port: process.env.PSCALE_DB_PORT ? process.env.PSCALE_DB_PORT : 3306,
17 18
 }
18 19
 
19
-const connectionSettings = process.env.USE_LOCAL_DB == "true" ? local : pscale
20
+const connectionSettings = process.env.USE_LOCAL_DB == 'true' ? local : pscale
20 21
 
21 22
 module.exports = {
22 23
     development: {
@@ -24,13 +25,13 @@ module.exports = {
24 25
         connection: connectionSettings,
25 26
         pool: {
26 27
             min: 2,
27
-            max: 10
28
+            max: 10,
28 29
         },
29 30
         migrations: {
30
-            directory: './db/migrations'
31
+            directory: './db/migrations',
31 32
         },
32 33
         seeds: {
33
-            directory: './db/seeds'
34
-        }
34
+            directory: './db/seeds',
35
+        },
35 36
     },
36 37
 }

+ 16
- 10
backend/package-lock.json Просмотреть файл

@@ -2057,14 +2057,20 @@
2057 2057
             }
2058 2058
         },
2059 2059
         "node_modules/caniuse-lite": {
2060
-            "version": "1.0.30001312",
2061
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz",
2062
-            "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==",
2060
+            "version": "1.0.30001423",
2061
+            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz",
2062
+            "integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==",
2063 2063
             "dev": true,
2064
-            "funding": {
2065
-                "type": "opencollective",
2066
-                "url": "https://opencollective.com/browserslist"
2067
-            }
2064
+            "funding": [
2065
+                {
2066
+                    "type": "opencollective",
2067
+                    "url": "https://opencollective.com/browserslist"
2068
+                },
2069
+                {
2070
+                    "type": "tidelift",
2071
+                    "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
2072
+                }
2073
+            ]
2068 2074
         },
2069 2075
         "node_modules/chalk": {
2070 2076
             "version": "3.0.0",
@@ -9889,9 +9895,9 @@
9889 9895
             "dev": true
9890 9896
         },
9891 9897
         "caniuse-lite": {
9892
-            "version": "1.0.30001418",
9893
-            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz",
9894
-            "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==",
9898
+            "version": "1.0.30001423",
9899
+            "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001423.tgz",
9900
+            "integrity": "sha512-09iwWGOlifvE1XuHokFMP7eR38a0JnajoyL3/i87c8ZjRWRrdKo1fqjNfugfBD0UDBIOz0U+jtNhJ0EPm1VleQ==",
9895 9901
             "dev": true
9896 9902
         },
9897 9903
         "chalk": {

+ 8
- 1
frontend/src/components/PairsList.vue Просмотреть файл

@@ -2,7 +2,14 @@
2 2
 section.pairs-list
3 3
     article(v-if='pairs.length')
4 4
         template(v-for='pair in pairs')
5
-            router-link.pair.w-flex.align-center.justify-space-around(:to='`/profile/${pair.profile.pid}`')
5
+            router-link.pair.w-flex.align-center.justify-space-around(
6
+                :to='`/profile/${pair.profile.pid}`'
7
+                v-if='tabName == "pending"'
8
+            )
9
+            router-link.pair.w-flex.align-center.justify-space-around(
10
+                :to='`/chat/${pair.profile.pid}`'
11
+                v-else
12
+            )
6 13
                 .dot--icon
7 14
                 .avatar
8 15
                 .idCard

+ 36
- 0
frontend/src/entities/chat-message/chat-message.js Просмотреть файл

@@ -0,0 +1,36 @@
1
+/** @module entities/chat-message */
2
+
3
+import { chatMessageSchema } from './chat-message.schema.js'
4
+
5
+/** Class representing a grouping */
6
+class ChatMessage {
7
+    /**
8
+     * Create the chatMessage for pubnub
9
+     * @param {string} message you message
10
+     * @return {ChatMessage} the message instance object
11
+     */
12
+    constructor(message) {
13
+        this.description = message
14
+        this.type = this.constructor.name.toLowerCase()
15
+    }
16
+    /**
17
+     * validate this record
18
+     * @return {boolean} is it valid or not?
19
+     */
20
+    isValid() {
21
+        const validate = chatMessageSchema.validate(this)
22
+
23
+        /**
24
+         * Log out some useful error messages
25
+         * TODO: Send validate.error to logging error handler
26
+         */
27
+        if (validate.error) {
28
+            console.error(`error: ${validate.error} - ${this.type} validation`)
29
+        }
30
+
31
+        /** validate(this) always returns something so force it to a bool */
32
+        return !validate.error ? true : false
33
+    }
34
+}
35
+
36
+export { ChatMessage }

+ 21
- 0
frontend/src/entities/chat-message/chat-message.schema.js Просмотреть файл

@@ -0,0 +1,21 @@
1
+/** @module entities/chatMessageSchema */
2
+import Joi from 'joi'
3
+
4
+/**
5
+ * chat message schema object
6
+ * for pubnub messages
7
+ * @constructor
8
+ */
9
+const chatMessageSchema = {
10
+    type: 'object',
11
+    properties: Joi.object().keys({
12
+        description: Joi.string(),
13
+    }),
14
+    /** fields required before saving */
15
+    required: ['description'],
16
+    validate(instance) {
17
+        return this.properties.validate(instance)
18
+    },
19
+}
20
+
21
+export { chatMessageSchema }

+ 1
- 0
frontend/src/entities/chat-message/index.js Просмотреть файл

@@ -0,0 +1 @@
1
+export * from './chat-message.js'

+ 1
- 0
frontend/src/entities/index.js Просмотреть файл

@@ -6,3 +6,4 @@ export * from './profile/index.js'
6 6
 export * from './survey/index.js'
7 7
 export * from './grouping/index.js'
8 8
 export * from './card/index.js'
9
+export * from './chat-message/index.js'

+ 32
- 28
frontend/src/services/chat.service.js Просмотреть файл

@@ -1,5 +1,9 @@
1 1
 import PubNub from 'pubnub'
2 2
 
3
+import { ChatMessage } from '../entities'
4
+
5
+const MAIN_CHANNEL = 'Channel-Siimee'
6
+
3 7
 /**
4 8
  * Provider method holder
5 9
  * We always reference this object so
@@ -8,17 +12,16 @@ import PubNub from 'pubnub'
8 12
  *
9 13
  * This gets overloaded later in the program
10 14
  */
11
-const providerMethods = {
15
+const _providerMethods = {
12 16
     publish: () => console.error('no provider publish method set'),
13 17
     subscribe: () => console.error('no provider subscribe method set'),
14 18
     listen: () => console.error('no provider listen method set'),
15 19
 }
20
+
16 21
 /**
17
- *
18
- *
19 22
  * Breaking out as much pubnub specific flavor
20 23
  */
21
-const setupPubnub = async uuid => {
24
+const _setupPubnub = async uuid => {
22 25
     const publishKey = import.meta.env.VITE_PUBNUB_PUBLISH_KEY
23 26
     const subscribeKey = import.meta.env.VITE_PUBNUB_SUBSCRIBE_KEY
24 27
 
@@ -31,20 +34,13 @@ const setupPubnub = async uuid => {
31 34
         uuid,
32 35
     })
33 36
     // Pass pubnub specific methods to our placeholder obj
34
-    providerMethods['publish'] = pubnubClient.publish
35
-    providerMethods['subscribe'] = pubnubClient.subscribe
36
-    providerMethods['listen'] = pubnubClient.addListener
37
+    _providerMethods['publish'] = pubnubClient.publish
38
+    _providerMethods['subscribe'] = pubnubClient.subscribe
39
+    _providerMethods['listen'] = pubnubClient.addListener
37 40
 
38 41
     return pubnubClient
39 42
 }
40 43
 
41
-class ChatMessage {
42
-    constructor(message) {
43
-        this.description = message
44
-    }
45
-}
46
-const MAIN_CHANNEL = 'Channel-Siimee'
47
-
48 44
 /** Singleton that holds all our chat information */
49 45
 class Chatter {
50 46
     /**
@@ -54,13 +50,8 @@ class Chatter {
54 50
     constructor() {
55 51
         // Our pubnub instance
56 52
         this.provider = null
57
-
58
-        // UUID used to identify unique users
59 53
         this.uuid = null
60
-
61
-        // Setup the main channel
62
-        //  subscriptions array will be built dynamically from the "this.groupings" object
63
-        this.subscriptions = [MAIN_CHANNEL]
54
+        this._subscriptions = [MAIN_CHANNEL]
64 55
 
65 56
         this.listeners = {
66 57
             status: async e => {
@@ -70,7 +61,19 @@ class Chatter {
70 61
             presence: this._onPresence,
71 62
         }
72 63
     }
64
+    get subscriptions() {
65
+        let truncated = this._subscriptions
66
+
67
+        // Do NOT include the main channel as part of subscriptions
68
+        const mainChanIndex = truncated.indexOf(MAIN_CHANNEL)
69
+        if (mainChanIndex > -1) {
70
+            truncated.splice(mainChanIndex, 1)
71
+        }
72
+
73
+        return truncated
74
+    }
73 75
     async _onPresence(e) {
76
+        console.log('presence :', e)
74 77
         return
75 78
     }
76 79
     setOnMessage(cb) {
@@ -79,13 +82,13 @@ class Chatter {
79 82
 
80 83
     async setup(uuid, groupings) {
81 84
         this.uuid = `${uuid}`
82
-        this.provider = await setupPubnub(this.uuid)
85
+        this.provider = await _setupPubnub(this.uuid)
83 86
 
84 87
         //  step_1: build the this.groupings object from the backend
85 88
         //  await for the groupings to be fetched before subscribing to channels
86 89
         await this._setupAllChannels(groupings)
87 90
         this._listenFor({ listeners: this.listeners })
88
-        this.subscribe({ channels: this.subscriptions })
91
+        this.subscribe({ channels: this._subscriptions })
89 92
         return this.subscriptions
90 93
     }
91 94
     /**
@@ -97,7 +100,7 @@ class Chatter {
97 100
      * @return {object} timestamp
98 101
      */
99 102
     async publish(channel, message) {
100
-        return providerMethods.publish({
103
+        return _providerMethods.publish({
101 104
             channel,
102 105
             message: new ChatMessage(message),
103 106
         })
@@ -108,26 +111,27 @@ class Chatter {
108 111
      * @param {array} channels
109 112
      */
110 113
     subscribe({ channels }) {
111
-        providerMethods.subscribe({ channels })
114
+        console.log('subscribing to:', channels)
115
+        _providerMethods.subscribe({ channels })
112 116
     }
113 117
     /**
114 118
      * Listen to events and set callbacks
115 119
      * Facade so we can hide provider specific methods
116 120
      */
117 121
     _listenFor({ listeners }) {
118
-        providerMethods.listen(listeners)
122
+        _providerMethods.listen(listeners)
119 123
     }
120 124
     //  step 2: build the this.subscriptions array from the this.groupings object
121 125
     // fetch all groupings for this profile and then store them in the chatter groupings object for reference
122 126
     async _setupAllChannels(groupings) {
123 127
         groupings.forEach(grouping => {
124
-            this.subscriptions.push(grouping.grouping_name)
128
+            this._subscriptions.push(grouping.grouping_name)
125 129
         })
126 130
     }
127 131
     stop() {
128
-        this.subscriptions = [MAIN_CHANNEL]
132
+        this._subscriptions = [MAIN_CHANNEL]
129 133
         console.warn('chatter stop not implemented')
130 134
     }
131 135
 }
132 136
 
133
-export { Chatter }
137
+export { Chatter, MAIN_CHANNEL }

+ 2
- 2
frontend/src/services/login.service.js Просмотреть файл

@@ -83,6 +83,7 @@ class Login {
83 83
 
84 84
         this._loading.value = false
85 85
         console.warn('logged in:', this.isLoggedIn)
86
+        console.warn('subscribed to:', this.chatter.subscriptions)
86 87
         return this.id.value
87 88
     }
88 89
     logout() {
@@ -136,8 +137,7 @@ class Login {
136 137
     async setupChatter() {
137 138
         this.chatter = new Chatter()
138 139
         // Use the reactive id object
139
-        const testAccountUUID = this.id.value
140
-        await this.chatter.setup(testAccountUUID, this.groupings)
140
+        await this.chatter.setup(this.id.value, this.groupings)
141 141
     }
142 142
 }
143 143
 

+ 27
- 22
frontend/src/views/ChatView.vue Просмотреть файл

@@ -1,29 +1,32 @@
1 1
 <template lang="pug">
2 2
 main.view--chat
3
-    header 
4
-        h2 Chat Page
5
- 
6
-    article(v-if="profile.isLoggedIn && target")
7
-        h3 {{ profile.id }} 
8
-            span chatting with: {{ target.profile_id }}
3
+    header(v-if='profile')
4
+        p {{ profile.chatter }}
5
+        hr
6
+        p messages: {{ messages }}
7
+        hr
9 8
         p subscriptions: {{ profile.chatter.subscriptions }}
10 9
 
11
-        ul(id="messages").w-flex.column
12
-            li(v-for="message, i in messages" class="pa1")
13
-                w-card.w-flex.row
14
-                    article
15
-                        p {{ message.message }}
16
-                    footer
17
-                        p {{ message.publisher }} | {{ message.timetoken }}
18
-                        w-button(class="my12" @click="openDrawer = i" text) setting
19
-                    w-drawer(v-model="openDrawer" absolute width="160px")
20
-                        p some settings things
10
+    article(v-if='profile.isLoggedIn && target')
11
+        h3 {{ profile.id }}&nbsp;
12
+            span chatting with: {{ target.profile_id }}
13
+
14
+        ul#messages.w-flex.column
15
+            //- li.pa1(v-for='(message, i in messages)')
16
+            //-     w-card.w-flex.row
17
+            //-         article
18
+                //- p {{ message.message }}
19
+        //-             footer
20
+        //-                 p {{ message.publisher }} | {{ message.timetoken }}
21
+        //-                 w-button.my12(@click='openDrawer = i' text) setting
22
+        //-             w-drawer(absolute v-model='openDrawer' width='160px')
23
+        //-                 p some settings things
21 24
 
22
-        input(v-model="toSend" @keyup.enter="sendMessage")
23
-        button(@click="sendMessage") send
25
+        input(@keyup.enter='sendMessage' v-model='toSend')
26
+        button(@click='sendMessage') send
24 27
 
25
-    p(v-else-if="profile.isLoggedIn && !target") No match found between profile {{ $route.params.pid }} and {{profile.id}}... 
26
-    w-spinner(v-else bounce)
28
+    p(v-else-if='profile.isLoggedIn && !target') No match found between profile {{ $route.params.pid }} and {{ profile.id }}...
29
+    w-spinner(bounce v-else)
27 30
 
28 31
     MainNav
29 32
 </template>
@@ -62,9 +65,10 @@ export default {
62 65
             if (!e.message) return
63 66
             this.messages.push(e)
64 67
         },
68
+        // TODO: test this
65 69
         getGrouping() {
66 70
             return currentProfile.groupings.find(
67
-                g => g.profile.profile_id == this.$route.params.tid,
71
+                g => g.profile.profile_id == this.$route.params.pid,
68 72
             )
69 73
         },
70 74
         sendMessage() {
@@ -72,13 +76,14 @@ export default {
72 76
             currentProfile.chatter.publish(grouping.grouping_name, this.toSend)
73 77
             this.toSend = ''
74 78
         },
79
+        // TODO: test this
75 80
         loadTargetProfile() {
76 81
             try {
77 82
                 const grouping = this.getGrouping()
78 83
                 if (!grouping) {
79 84
                     throw `no match found for ${currentProfile.id.value}`
80 85
                 }
81
-
86
+                console.log('grouping :', grouping)
82 87
                 this.target = grouping.profile
83 88
             } catch (err) {
84 89
                 console.error(err)

Загрузка…
Отмена
Сохранить