Gitter migration: Setup redirects (rollout pt. 3)
[gitter.git] / server / handlers / renderers / chat-internal.js
blob98985f0ae7784d05bf2a5fd3d2819acf0438a1b3
1 'use strict';
3 var env = require('gitter-web-env');
4 var nconf = env.config;
5 var Promise = require('bluebird');
6 var _ = require('lodash');
7 const asyncHandler = require('express-async-handler');
9 const mongoUtils = require('gitter-web-persistence-utils/lib/mongo-utils');
10 var contextGenerator = require('../../web/context-generator');
11 var restful = require('../../services/restful');
12 var burstCalculator = require('../../utils/burst-calculator');
13 const userSort = require('gitter-web-shared/sorting/user-sort');
14 var getSubResources = require('./sub-resources');
15 var fixMongoIdQueryParam = require('../../web/fix-mongo-id-query-param');
16 var fonts = require('../../web/fonts');
17 var generateRightToolbarSnapshot = require('../snapshots/right-toolbar-snapshot');
18 var generateUserThemeSnapshot = require('../snapshots/user-theme-snapshot');
19 var getHeaderViewOptions = require('gitter-web-shared/templates/get-header-view-options');
20 const mixinHbsDataForVueLeftMenu = require('./vue/mixin-vue-left-menu-data');
21 const getChatSnapshotOptions = require('./chat/chat-snapshot-options');
22 const socialMetadataGenerator = require('../social-metadata-generator');
24 const ROSTER_SIZE = 25;
26 const getPermalinkMessageId = request => fixMongoIdQueryParam(request.query.at);
28 function getSocialMetaDataForRoom(room, permalinkChatSerialized) {
29   let socialMetadata;
30   if (room && permalinkChatSerialized) {
31     socialMetadata = socialMetadataGenerator.getMetadataForChatPermalink({
32       room,
33       chat: permalinkChatSerialized
34     });
35   } else if (room) {
36     socialMetadata = socialMetadataGenerator.getMetadata({ room });
37   }
39   return socialMetadata;
42 // eslint-disable-next-line max-statements, complexity
43 async function renderChat(req, res, next, options) {
44   const { uriContext, embedded } = options;
46   var troupe = uriContext.troupe;
47   var user = req.user;
48   var userId = user && user.id;
50   const userSerializerOptions = {
51     lean: true,
52     limit: ROSTER_SIZE
53   };
54   const chatSnapshotOptions = await getChatSnapshotOptions(userId, troupe.id, req);
56   const permalinkChatId = getPermalinkMessageId(req);
58   const [
59     troupeContext,
60     chats,
61     activityEvents,
62     users,
63     rightToolbarSnapshot,
64     userThemeSnapshot
65   ] = await Promise.all([
66     contextGenerator.generateTroupeContext(req, {
67       snapshots: { chat: chatSnapshotOptions },
68       permalinkChatId,
69       // Are we using /~embed ?
70       embedded
71     }),
72     restful.serializeChatsForTroupe(troupe.id, userId, chatSnapshotOptions),
73     options.fetchEvents === false ? null : restful.serializeEventsForTroupe(troupe.id, userId),
74     options.fetchUsers === false
75       ? null
76       : restful.serializeUsersForTroupe(troupe.id, userId, userSerializerOptions),
77     generateRightToolbarSnapshot(req),
78     generateUserThemeSnapshot(req)
79   ]);
81   var initialChat = _.find(chats, function(chat) {
82     return chat.initial;
83   });
84   var initialBottom = !initialChat;
86   const permalinkChatSerialized = _.find(chats, function(chat) {
87     return mongoUtils.objectIDsEqual(chat.id, permalinkChatId);
88   });
90   var classNames = options.classNames || [];
91   var isStaff = req.user && req.user.staff;
93   troupeContext.snapshots = {
94     rightToolbar: rightToolbarSnapshot
95   };
97   if (!user) classNames.push('logged-out');
99   var integrationsUrl;
101   if (troupeContext && troupeContext.isNativeDesktopApp) {
102     integrationsUrl = nconf.get('web:basepath') + '/' + troupeContext.troupe.uri + '#integrations';
103   } else {
104     integrationsUrl = '#integrations';
105   }
107   const script = options.script;
108   var cssFileName = options.stylesheet
109     ? 'styles/' + options.stylesheet + '.css'
110     : 'styles/' + script + '.css'; // css filename matches bootscript
112   var chatsWithBurst = burstCalculator(chats);
113   if (options.filterChats) {
114     chatsWithBurst = options.filterChats(chatsWithBurst);
115   }
117   /* This is less than ideal way of checking if the user is the admin */
118   var isAdmin =
119     troupeContext.troupe &&
120     troupeContext.troupe.permissions &&
121     troupeContext.troupe.permissions.admin;
123   var isRightToolbarPinned = rightToolbarSnapshot && rightToolbarSnapshot.isPinned;
124   if (isRightToolbarPinned === undefined) {
125     isRightToolbarPinned = true;
126   }
128   const socialMetadata = getSocialMetaDataForRoom(troupeContext.troupe, permalinkChatSerialized);
130   var renderOptions = await mixinHbsDataForVueLeftMenu(
131     req,
132     _.extend(
133       {
134         embedded: options.embedded || false,
135         hasDarkTheme: userThemeSnapshot.theme === 'gitter-dark',
136         hasCachedFonts: fonts.hasCachedFonts(req.cookies),
137         fonts: fonts.getFonts(),
138         socialMetadata,
139         isRepo: troupe.sd.type === 'GH_REPO', // Used by chat_toolbar patial
140         bootScriptName: script,
141         cssFileName: cssFileName,
142         troupeName: uriContext.uri,
143         oneToOne: troupe.oneToOne, // Used by the old left menu
144         user: user,
145         troupeContext: troupeContext,
146         initialBottom: initialBottom,
147         chats: chatsWithBurst,
148         classNames: classNames.join(' '),
149         subresources: getSubResources(script),
150         activityEvents: activityEvents,
151         users: users && users.sort(userSort),
152         userCount: troupe.userCount,
153         hasHiddenMembers: troupe.userCount > 25,
154         integrationsUrl: integrationsUrl,
155         isMobile: options.isMobile,
156         roomMember: uriContext.roomMember,
157         isRightToolbarPinned: isRightToolbarPinned,
158         matrixRoomLink: troupeContext.troupe.matrixRoomLink,
159         elementUrl: nconf.get('element:appUrl'),
161         //Feature Switch Left Menu
162         troupeTopic: troupeContext.troupe.topic,
163         premium: troupeContext.troupe.premium,
164         troupeFavourite: troupeContext.troupe.favourite,
165         headerView: getHeaderViewOptions(troupeContext.troupe),
166         canChangeGroupAvatar: !!troupe.groupId && (isStaff || isAdmin),
167         isAdmin: isAdmin,
168         isNativeDesktopApp: troupeContext.isNativeDesktopApp
169       },
170       options.extras
171     )
172   );
174   res.render(options.template, renderOptions);
177 module.exports = asyncHandler(renderChat);