Browse Source

feat(Avatar): Implement Avatar for web

j8
hristoterezov 8 years ago
parent
commit
814bd26c07

+ 60
- 16
conference.js View File

20
 
20
 
21
 import EventEmitter from "events";
21
 import EventEmitter from "events";
22
 
22
 
23
-import { conferenceFailed } from './react/features/base/conference';
23
+import {
24
+    CONFERENCE_JOINED,
25
+    conferenceFailed,
26
+    conferenceLeft
27
+} from './react/features/base/conference';
24
 import {
28
 import {
25
     isFatalJitsiConnectionError
29
     isFatalJitsiConnectionError
26
 } from './react/features/base/lib-jitsi-meet';
30
 } from './react/features/base/lib-jitsi-meet';
29
     suspendDetected
33
     suspendDetected
30
 } from './react/features/overlay';
34
 } from './react/features/overlay';
31
 
35
 
36
+import {
37
+    changeParticipantAvatarID,
38
+    changeParticipantAvatarURL,
39
+    changeParticipantEmail,
40
+    participantJoined,
41
+    participantLeft,
42
+    participantRoleChanged
43
+} from './react/features/base/participants';
44
+
32
 const ConnectionEvents = JitsiMeetJS.events.connection;
45
 const ConnectionEvents = JitsiMeetJS.events.connection;
33
 const ConnectionErrors = JitsiMeetJS.errors.connection;
46
 const ConnectionErrors = JitsiMeetJS.errors.connection;
34
 
47
 
150
     room.sendCommand(command, {value: value});
163
     room.sendCommand(command, {value: value});
151
 }
164
 }
152
 
165
 
166
+/**
167
+ * Setups initially the properties for the local participant - email, avatarId,
168
+ * avatarUrl, displayName, etc.
169
+ */
170
+function _setupLocalParticipantProperties() {
171
+    const email = APP.settings.getEmail();
172
+    email && sendData(commands.EMAIL, email);
173
+
174
+    const avatarUrl = APP.settings.getAvatarUrl();
175
+    avatarUrl && sendData(commands.AVATAR_URL, avatarUrl);
176
+
177
+    if(!email && !avatarUrl) {
178
+        sendData(commands.AVATAR_ID, APP.settings.getAvatarId());
179
+    }
180
+
181
+    let nick = APP.settings.getDisplayName();
182
+    if (config.useNicks && !nick) {
183
+        nick = APP.UI.askForNickname();
184
+        APP.settings.setDisplayName(nick);
185
+    }
186
+    nick && room.setDisplayName(nick);
187
+}
188
+
153
 /**
189
 /**
154
  * Get user nickname by user id.
190
  * Get user nickname by user id.
155
  * @param {string} id user id
191
  * @param {string} id user id
875
         this.invite = new Invite(room);
911
         this.invite = new Invite(room);
876
         this._room = room; // FIXME do not use this
912
         this._room = room; // FIXME do not use this
877
 
913
 
878
-        let email = APP.settings.getEmail();
879
-        email && sendData(this.commands.defaults.EMAIL, email);
880
-
881
-        let avatarUrl = APP.settings.getAvatarUrl();
882
-        avatarUrl && sendData(this.commands.defaults.AVATAR_URL,
883
-            avatarUrl);
884
-        !email && sendData(
885
-             this.commands.defaults.AVATAR_ID, APP.settings.getAvatarId());
886
-
887
-        let nick = APP.settings.getDisplayName();
888
-        if (config.useNicks && !nick) {
889
-            nick = APP.UI.askForNickname();
890
-            APP.settings.setDisplayName(nick);
891
-        }
892
-        nick && room.setDisplayName(nick);
914
+        _setupLocalParticipantProperties();
893
 
915
 
894
         this._setupListeners();
916
         this._setupListeners();
895
     },
917
     },
1116
     _setupListeners () {
1138
     _setupListeners () {
1117
         // add local streams when joined to the conference
1139
         // add local streams when joined to the conference
1118
         room.on(ConferenceEvents.CONFERENCE_JOINED, () => {
1140
         room.on(ConferenceEvents.CONFERENCE_JOINED, () => {
1141
+            APP.store.dispatch({
1142
+                type: CONFERENCE_JOINED,
1143
+                conference: room
1144
+            });
1119
             APP.UI.mucJoined();
1145
             APP.UI.mucJoined();
1120
             APP.API.notifyConferenceJoined(APP.conference.roomName);
1146
             APP.API.notifyConferenceJoined(APP.conference.roomName);
1121
             APP.UI.markVideoInterrupted(false);
1147
             APP.UI.markVideoInterrupted(false);
1122
         });
1148
         });
1123
 
1149
 
1150
+        room.on(ConferenceEvents.CONFERENCE_LEFT,
1151
+            (...args) => APP.store.dispatch(conferenceLeft(room, ...args)));
1152
+
1124
         room.on(
1153
         room.on(
1125
             ConferenceEvents.AUTH_STATUS_CHANGED,
1154
             ConferenceEvents.AUTH_STATUS_CHANGED,
1126
             function (authEnabled, authLogin) {
1155
             function (authEnabled, authLogin) {
1134
             if (user.isHidden())
1163
             if (user.isHidden())
1135
                 return;
1164
                 return;
1136
 
1165
 
1166
+            APP.store.dispatch(participantJoined({
1167
+                id,
1168
+                name: user.getDisplayName(),
1169
+                role: user.getRole()
1170
+            }));
1171
+
1137
             logger.log('USER %s connnected', id, user);
1172
             logger.log('USER %s connnected', id, user);
1138
             APP.API.notifyUserJoined(id);
1173
             APP.API.notifyUserJoined(id);
1139
             APP.UI.addUser(user);
1174
             APP.UI.addUser(user);
1142
             APP.UI.updateUserRole(user);
1177
             APP.UI.updateUserRole(user);
1143
         });
1178
         });
1144
         room.on(ConferenceEvents.USER_LEFT, (id, user) => {
1179
         room.on(ConferenceEvents.USER_LEFT, (id, user) => {
1180
+            APP.store.dispatch(participantLeft(id, user));
1145
             logger.log('USER %s LEFT', id, user);
1181
             logger.log('USER %s LEFT', id, user);
1146
             APP.API.notifyUserLeft(id);
1182
             APP.API.notifyUserLeft(id);
1147
             APP.UI.removeUser(id, user.getDisplayName());
1183
             APP.UI.removeUser(id, user.getDisplayName());
1150
 
1186
 
1151
 
1187
 
1152
         room.on(ConferenceEvents.USER_ROLE_CHANGED, (id, role) => {
1188
         room.on(ConferenceEvents.USER_ROLE_CHANGED, (id, role) => {
1189
+            APP.store.dispatch(participantRoleChanged(id, role));
1153
             if (this.isLocalId(id)) {
1190
             if (this.isLocalId(id)) {
1154
                 logger.info(`My role changed, new role: ${role}`);
1191
                 logger.info(`My role changed, new role: ${role}`);
1155
                 if (this.isModerator !== room.isModerator()) {
1192
                 if (this.isModerator !== room.isModerator()) {
1411
 
1448
 
1412
         APP.UI.addListener(UIEvents.EMAIL_CHANGED, this.changeLocalEmail);
1449
         APP.UI.addListener(UIEvents.EMAIL_CHANGED, this.changeLocalEmail);
1413
         room.addCommandListener(this.commands.defaults.EMAIL, (data, from) => {
1450
         room.addCommandListener(this.commands.defaults.EMAIL, (data, from) => {
1451
+            APP.store.dispatch(changeParticipantEmail(from, data.value));
1414
             APP.UI.setUserEmail(from, data.value);
1452
             APP.UI.setUserEmail(from, data.value);
1415
         });
1453
         });
1416
 
1454
 
1417
         room.addCommandListener(
1455
         room.addCommandListener(
1418
             this.commands.defaults.AVATAR_URL,
1456
             this.commands.defaults.AVATAR_URL,
1419
             (data, from) => {
1457
             (data, from) => {
1458
+                APP.store.dispatch(
1459
+                    changeParticipantAvatarURL(from, data.value));
1420
                 APP.UI.setUserAvatarUrl(from, data.value);
1460
                 APP.UI.setUserAvatarUrl(from, data.value);
1421
         });
1461
         });
1422
 
1462
 
1423
         room.addCommandListener(this.commands.defaults.AVATAR_ID,
1463
         room.addCommandListener(this.commands.defaults.AVATAR_ID,
1424
             (data, from) => {
1464
             (data, from) => {
1465
+                APP.store.dispatch(
1466
+                    changeParticipantAvatarID(from, data.value));
1425
                 APP.UI.setUserAvatarID(from, data.value);
1467
                 APP.UI.setUserAvatarID(from, data.value);
1426
             });
1468
             });
1427
 
1469
 
1832
         if (email === APP.settings.getEmail()) {
1874
         if (email === APP.settings.getEmail()) {
1833
             return;
1875
             return;
1834
         }
1876
         }
1877
+        APP.store.dispatch(changeParticipantEmail(room.myUserId(), email));
1835
 
1878
 
1836
         APP.settings.setEmail(email);
1879
         APP.settings.setEmail(email);
1837
         APP.UI.setUserEmail(room.myUserId(), email);
1880
         APP.UI.setUserEmail(room.myUserId(), email);
1848
         if (url === APP.settings.getAvatarUrl()) {
1891
         if (url === APP.settings.getAvatarUrl()) {
1849
             return;
1892
             return;
1850
         }
1893
         }
1894
+        APP.store.dispatch(changeParticipantAvatarURL(room.myUserId(), url));
1851
 
1895
 
1852
         APP.settings.setAvatarUrl(url);
1896
         APP.settings.setAvatarUrl(url);
1853
         APP.UI.setUserAvatarUrl(room.myUserId(), url);
1897
         APP.UI.setUserAvatarUrl(room.myUserId(), url);

+ 10
- 52
modules/UI/avatar/Avatar.js View File

21
  * SOFTWARE.
21
  * SOFTWARE.
22
  */
22
  */
23
 
23
 
24
-/* global MD5, config, interfaceConfig, APP */
25
-const logger = require("jitsi-meet-logger").getLogger(__filename);
24
+/* global APP */
25
+
26
+import { getAvatarURL } from '../../../react/features/base/participants';
26
 
27
 
27
 let users = {};
28
 let users = {};
28
 
29
 
64
      * @param url the url for the avatar
65
      * @param url the url for the avatar
65
      */
66
      */
66
     setUserAvatarUrl: function (id, url) {
67
     setUserAvatarUrl: function (id, url) {
67
-        this._setUserProp(id, "url", url);
68
+        this._setUserProp(id, "avatarUrl", url);
68
     },
69
     },
69
 
70
 
70
     /**
71
     /**
82
      * @param {string} userId user id
83
      * @param {string} userId user id
83
      */
84
      */
84
     getAvatarUrl: function (userId) {
85
     getAvatarUrl: function (userId) {
85
-        if (config.disableThirdPartyRequests) {
86
-            return 'images/avatar2.png';
87
-        }
88
-
86
+        let user;
89
         if (!userId || APP.conference.isLocalId(userId)) {
87
         if (!userId || APP.conference.isLocalId(userId)) {
90
-            userId = "local";
91
-        }
92
-
93
-        let avatarId = null;
94
-        const user = users[userId];
95
-
96
-        // The priority is url, email and lowest is avatarId
97
-        if(user) {
98
-            if(user.url)
99
-                return user.url;
100
-
101
-            if (user.email)
102
-                avatarId = user.email;
103
-            else {
104
-                avatarId = user.avatarId;
105
-            }
106
-        }
107
-
108
-        // If the ID looks like an email, we'll use gravatar.
109
-        // Otherwise, it's a random avatar, and we'll use the configured
110
-        // URL.
111
-        let random = !avatarId || avatarId.indexOf('@') < 0;
112
-
113
-        if (!avatarId) {
114
-            logger.warn(
115
-                `No avatar stored yet for ${userId} - using ID as avatar ID`);
116
-            avatarId = userId;
117
-        }
118
-        avatarId = MD5.hexdigest(avatarId.trim().toLowerCase());
119
-
120
-
121
-        let urlPref = null;
122
-        let urlSuf = null;
123
-        if (!random) {
124
-            urlPref = 'https://www.gravatar.com/avatar/';
125
-            urlSuf = "?d=wavatar&size=200";
126
-        }
127
-        else if (random && interfaceConfig.RANDOM_AVATAR_URL_PREFIX) {
128
-            urlPref = interfaceConfig.RANDOM_AVATAR_URL_PREFIX;
129
-            urlSuf = interfaceConfig.RANDOM_AVATAR_URL_SUFFIX;
130
-        }
131
-        else {
132
-            urlPref = 'https://api.adorable.io/avatars/200/';
133
-            urlSuf = ".png";
88
+            user = users.local;
89
+            userId = APP.conference.getMyUserId();
90
+        } else {
91
+            user = users[userId];
134
         }
92
         }
135
 
93
 
136
-        return urlPref + avatarId + urlSuf;
94
+        return getAvatarURL(userId, user);
137
     }
95
     }
138
 };
96
 };

+ 5
- 1
react/features/app/components/AbstractApp.js View File

78
 
78
 
79
         dispatch(appWillMount(this));
79
         dispatch(appWillMount(this));
80
 
80
 
81
-        dispatch(localParticipantJoined());
81
+        dispatch(localParticipantJoined({
82
+            avatarId: APP.settings.getAvatarId(),
83
+            avatarUrl: APP.settings.getAvatarUrl(),
84
+            email: APP.settings.getEmail()
85
+        }));
82
 
86
 
83
         // If a URL was explicitly specified to this React Component, then open
87
         // If a URL was explicitly specified to this React Component, then open
84
         // it; otherwise, use a default.
88
         // it; otherwise, use a default.

+ 2
- 2
react/features/base/conference/actions.js View File

38
             (...args) => dispatch(_conferenceJoined(conference, ...args)));
38
             (...args) => dispatch(_conferenceJoined(conference, ...args)));
39
     conference.on(
39
     conference.on(
40
             JitsiConferenceEvents.CONFERENCE_LEFT,
40
             JitsiConferenceEvents.CONFERENCE_LEFT,
41
-            (...args) => dispatch(_conferenceLeft(conference, ...args)));
41
+            (...args) => dispatch(conferenceLeft(conference, ...args)));
42
 
42
 
43
     conference.on(
43
     conference.on(
44
             JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
44
             JitsiConferenceEvents.DOMINANT_SPEAKER_CHANGED,
131
  *      conference: JitsiConference
131
  *      conference: JitsiConference
132
  *  }}
132
  *  }}
133
  */
133
  */
134
-function _conferenceLeft(conference) {
134
+export function conferenceLeft(conference) {
135
     return {
135
     return {
136
         type: CONFERENCE_LEFT,
136
         type: CONFERENCE_LEFT,
137
         conference
137
         conference

+ 46
- 1
react/features/base/participants/actions.js View File

8
 } from './actionTypes';
8
 } from './actionTypes';
9
 import { getLocalParticipant } from './functions';
9
 import { getLocalParticipant } from './functions';
10
 
10
 
11
+/**
12
+ * Action to update a participant's avatar id.
13
+ *
14
+ * @param {string} id - Participant's id.
15
+ * @param {string} avatarId - Participant's avatar id.
16
+ * @returns {{
17
+ *      type: PARTICIPANT_UPDATED,
18
+ *      participant: {
19
+ *          id: string,
20
+ *          avatarId: string,
21
+ *      }
22
+ * }}
23
+ */
24
+export function changeParticipantAvatarID(id, avatarId) {
25
+    return {
26
+        type: PARTICIPANT_UPDATED,
27
+        participant: {
28
+            id,
29
+            avatarId
30
+        }
31
+    };
32
+}
33
+
34
+/**
35
+ * Action to update a participant's avatar URL.
36
+ *
37
+ * @param {string} id - Participant's id.
38
+ * @param {string} url - Participant's avatar url.
39
+ * @returns {{
40
+ *      type: PARTICIPANT_UPDATED,
41
+ *      participant: {
42
+ *          id: string,
43
+ *          url: string,
44
+ *      }
45
+ * }}
46
+ */
47
+export function changeParticipantAvatarURL(id, url) {
48
+    return {
49
+        type: PARTICIPANT_UPDATED,
50
+        participant: {
51
+            id,
52
+            url
53
+        }
54
+    };
55
+}
56
+
11
 /**
57
 /**
12
  * Action to update a participant's email.
58
  * Action to update a participant's email.
13
  *
59
  *
17
  *      type: PARTICIPANT_UPDATED,
63
  *      type: PARTICIPANT_UPDATED,
18
  *      participant: {
64
  *      participant: {
19
  *          id: string,
65
  *          id: string,
20
- *          avatar: string,
21
  *          email: string
66
  *          email: string
22
  *      }
67
  *      }
23
  * }}
68
  * }}

+ 32
- 0
react/features/base/participants/components/Avatar.web.js View File

1
+import React, { Component } from 'react';
2
+
3
+/**
4
+ * Display a participant avatar.
5
+ */
6
+export default class Avatar extends Component {
7
+    /**
8
+     * Avatar component's property types.
9
+     *
10
+     * @static
11
+     */
12
+    static propTypes = {
13
+        /**
14
+         * The URL for the avatar.
15
+         *
16
+         * @type {string}
17
+         */
18
+        uri: React.PropTypes.string
19
+    }
20
+
21
+    /**
22
+     * Implements React's {@link Component#render()}.
23
+     *
24
+     * @inheritdoc
25
+     */
26
+    render() {
27
+        return (
28
+            <img
29
+                src = { this.props.uri } />
30
+        );
31
+    }
32
+}

+ 1
- 0
react/features/base/participants/components/index.js View File

1
+export { default as Avatar } from './Avatar';
1
 export { default as ParticipantView } from './ParticipantView';
2
 export { default as ParticipantView } from './ParticipantView';

+ 72
- 0
react/features/base/participants/functions.js View File

1
+/* global MD5 */
2
+
3
+declare var config: Object;
4
+declare var interfaceConfig: Object;
5
+
1
 /**
6
 /**
2
  * Returns local participant from Redux state.
7
  * Returns local participant from Redux state.
3
  *
8
  *
45
 
50
 
46
     return participants || [];
51
     return participants || [];
47
 }
52
 }
53
+
54
+/**
55
+ * Returns the URL of the image for the avatar of a particular participant
56
+ * identified by their id and/or e-mail address.
57
+ *
58
+ * @param {string} [participantId] - Participant's id.
59
+ * @param {Object} [options] - The optional arguments.
60
+ * @param {string} [options.avatarId] - Participant's avatar id.
61
+ * @param {string} [options.avatarUrl] - Participant's avatar url.
62
+ * @param {string} [options.email] - Participant's email.
63
+ * @returns {string} The URL of the image for the avatar of the participant
64
+ * identified by the specified participantId and/or email.
65
+ *
66
+ * @public
67
+ */
68
+export function getAvatarURL(participantId, options = {}) {
69
+    // If disableThirdPartyRequests is enabled we shouldn't use third party
70
+    // avatar services, we are returning one of our images.
71
+    if (typeof config === 'object' && config.disableThirdPartyRequests) {
72
+        return 'images/avatar2.png';
73
+    }
74
+
75
+    const { avatarId, avatarUrl, email } = options;
76
+
77
+    // If we have avatarUrl we don't need to generate new one.
78
+    if (avatarUrl) {
79
+        return avatarUrl;
80
+    }
81
+
82
+    let avatarKey = null;
83
+
84
+    if (email) {
85
+        avatarKey = email;
86
+    } else {
87
+        avatarKey = avatarId;
88
+    }
89
+
90
+    // If the ID looks like an email, we'll use gravatar.
91
+    // Otherwise, it's a random avatar, and we'll use the configured
92
+    // URL.
93
+    const isEmail = avatarKey && avatarKey.indexOf('@') > 0;
94
+
95
+    if (!avatarKey) {
96
+        avatarKey = participantId;
97
+    }
98
+
99
+    avatarKey = MD5.hexdigest(avatarKey.trim().toLowerCase());
100
+
101
+    let urlPref = null;
102
+    let urlSuf = null;
103
+
104
+    // gravatar doesn't support random avatars that's why we need to use other
105
+    // services for the use case when the email is undefined.
106
+    if (isEmail) {
107
+        urlPref = 'https://www.gravatar.com/avatar/';
108
+        urlSuf = '?d=wavatar&size=200';
109
+    } else if (typeof interfaceConfig === 'object'
110
+        && interfaceConfig.RANDOM_AVATAR_URL_PREFIX) { // custom avatar service
111
+        urlPref = interfaceConfig.RANDOM_AVATAR_URL_PREFIX;
112
+        urlSuf = interfaceConfig.RANDOM_AVATAR_URL_SUFFIX;
113
+    } else { // default avatar service
114
+        urlPref = 'https://api.adorable.io/avatars/200/';
115
+        urlSuf = '.png';
116
+    }
117
+
118
+    return urlPref + avatarKey + urlSuf;
119
+}

+ 22
- 47
react/features/base/participants/reducer.js View File

1
-/* global MD5 */
2
-
3
 import { ReducerRegistry, setStateProperty } from '../redux';
1
 import { ReducerRegistry, setStateProperty } from '../redux';
4
 
2
 
5
 import {
3
 import {
14
     LOCAL_PARTICIPANT_DEFAULT_ID,
12
     LOCAL_PARTICIPANT_DEFAULT_ID,
15
     PARTICIPANT_ROLE
13
     PARTICIPANT_ROLE
16
 } from './constants';
14
 } from './constants';
15
+import { getAvatarURL } from './functions';
17
 
16
 
18
 /**
17
 /**
19
  * Participant object.
18
  * Participant object.
64
     case PARTICIPANT_ID_CHANGED:
63
     case PARTICIPANT_ID_CHANGED:
65
         if (state.id === action.oldValue) {
64
         if (state.id === action.oldValue) {
66
             const id = action.newValue;
65
             const id = action.newValue;
66
+            const { avatarId, avatarUrl, email } = state;
67
 
67
 
68
             return {
68
             return {
69
                 ...state,
69
                 ...state,
70
                 id,
70
                 id,
71
-                avatar: state.avatar || _getAvatarURL(id, state.email)
71
+                avatar: state.avatar || getAvatarURL(id, {
72
+                    avatarId,
73
+                    avatarUrl,
74
+                    email
75
+                })
72
             };
76
             };
73
         }
77
         }
74
         break;
78
         break;
81
         const id
85
         const id
82
             = participant.id
86
             = participant.id
83
                 || (participant.local && LOCAL_PARTICIPANT_DEFAULT_ID);
87
                 || (participant.local && LOCAL_PARTICIPANT_DEFAULT_ID);
88
+        const { avatarId, avatarUrl, email } = participant;
84
         const avatar
89
         const avatar
85
-            = participant.avatar || _getAvatarURL(id, participant.email);
90
+            = participant.avatar
91
+                || getAvatarURL(id, {
92
+                    avatarId,
93
+                    avatarUrl,
94
+                    email
95
+                });
86
 
96
 
87
         // TODO Get these names from config/localized.
97
         // TODO Get these names from config/localized.
88
         const name
98
         const name
90
 
100
 
91
         return {
101
         return {
92
             avatar,
102
             avatar,
93
-            email: participant.email,
103
+            email,
94
             id,
104
             id,
95
             local: participant.local || false,
105
             local: participant.local || false,
96
             name,
106
             name,
113
             }
123
             }
114
 
124
 
115
             if (!newState.avatar) {
125
             if (!newState.avatar) {
116
-                newState.avatar
117
-                    = _getAvatarURL(action.participant.id, newState.email);
126
+                const { avatarId, avatarUrl, email } = newState;
127
+
128
+                newState.avatar = getAvatarURL(action.participant.id, {
129
+                    avatarId,
130
+                    avatarUrl,
131
+                    email
132
+                });
118
             }
133
             }
119
 
134
 
120
             return newState;
135
             return newState;
162
         return state;
177
         return state;
163
     }
178
     }
164
 });
179
 });
165
-
166
-/**
167
- * Returns the URL of the image for the avatar of a particular participant
168
- * identified by their id and/or e-mail address.
169
- *
170
- * @param {string} participantId - Participant's id.
171
- * @param {string} [email] - Participant's email.
172
- * @returns {string} The URL of the image for the avatar of the participant
173
- * identified by the specified participantId and/or email.
174
- */
175
-function _getAvatarURL(participantId, email) {
176
-    // TODO: Use disableThirdPartyRequests config.
177
-
178
-    let avatarId = email || participantId;
179
-
180
-    // If the ID looks like an email, we'll use gravatar. Otherwise, it's a
181
-    // random avatar and we'll use the configured URL.
182
-    const random = !avatarId || avatarId.indexOf('@') < 0;
183
-
184
-    if (!avatarId) {
185
-        avatarId = participantId;
186
-    }
187
-
188
-    // MD5 is provided by Strophe
189
-    avatarId = MD5.hexdigest(avatarId.trim().toLowerCase());
190
-
191
-    let urlPref = null;
192
-    let urlSuf = null;
193
-
194
-    if (random) {
195
-        // TODO: Use RANDOM_AVATAR_URL_PREFIX from interface config.
196
-        urlPref = 'https://robohash.org/';
197
-        urlSuf = '.png?size=200x200';
198
-    } else {
199
-        urlPref = 'https://www.gravatar.com/avatar/';
200
-        urlSuf = '?d=wavatar&size=200';
201
-    }
202
-
203
-    return urlPref + avatarId + urlSuf;
204
-}

Loading…
Cancel
Save