• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

u-wave / core / 11085094286

28 Sep 2024 03:39PM UTC coverage: 79.715% (-0.4%) from 80.131%
11085094286

Pull #637

github

web-flow
Merge 11ccf3b06 into 14c162f19
Pull Request #637: Switch to a relational database, closes #549

751 of 918 branches covered (81.81%)

Branch coverage included in aggregate %.

1891 of 2530 new or added lines in 50 files covered. (74.74%)

13 existing lines in 7 files now uncovered.

9191 of 11554 relevant lines covered (79.55%)

68.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.06
/src/controllers/now.js
1
import { getBoothData } from './booth.js';
1✔
2
import { serializePlaylist, serializeUser } from '../utils/serialize.js';
1✔
3
import { legacyPlaylistItem } from './playlists.js';
1✔
4

1✔
5
/**
1✔
6
 * @typedef {import('../schema.js').UserID} UserID
1✔
7
 */
1✔
8

1✔
9
/**
1✔
10
 * @param {import('../Uwave.js').default} uw
1✔
11
 * @param {import('../schema.js').Playlist & { size: number }} playlist
1✔
12
 */
1✔
13
async function getFirstItem(uw, playlist) {
1✔
14
  try {
1✔
15
    if (playlist.size > 0) {
1!
NEW
16
      const { playlistItem, media } = await uw.playlists.getPlaylistItemAt(playlist, 0);
×
NEW
17
      return legacyPlaylistItem(playlistItem, media);
×
UNCOV
18
    }
×
19
  } catch (e) {
1!
20
    // Nothing
×
21
  }
×
22
  return null;
1✔
23
}
1✔
24

1✔
25
/**
1✔
26
 * @param {unknown} str
1✔
27
 */
1✔
28
function toInt(str) {
3✔
29
  if (typeof str !== 'string') return 0;
3✔
30
  if (!/^\d+$/.test(str)) return 0;
×
31
  return parseInt(str, 10);
×
32
}
3✔
33

1✔
34
/**
1✔
35
 * @param {import('../Uwave.js').default} uw
1✔
36
 */
1✔
37
async function getOnlineUsers(uw) {
3✔
38
  const userIDs = /** @type {UserID[]} */ (await uw.redis.lrange('users', 0, -1));
3✔
39
  if (userIDs.length === 0) {
3✔
40
    return [];
3✔
41
  }
3✔
UNCOV
42

×
NEW
43
  const users = await uw.users.getUsersByIds(userIDs);
×
UNCOV
44
  return users.map(serializeUser);
×
45
}
3✔
46

1✔
47
/**
1✔
48
 * @param {import('../Uwave.js').default} uw
1✔
49
 */
1✔
50
async function getGuestsCount(uw) {
3✔
51
  const guests = await uw.redis.get('http-api:guests');
3✔
52
  return toInt(guests);
3✔
53
}
3✔
54

1✔
55
/**
1✔
56
 * @type {import('../types.js').Controller}
1✔
57
 */
1✔
58
async function getState(req) {
3✔
59
  const uw = req.uwave;
3✔
60
  const { authRegistry } = req.uwaveHttp;
3✔
61
  const { passport } = uw;
3✔
62
  const { user } = req;
3✔
63

3✔
64
  const motd = uw.motd.get();
3✔
65
  const users = getOnlineUsers(uw);
3✔
66
  const guests = getGuestsCount(uw);
3✔
67
  const roles = uw.acl.getAllRoles();
3✔
68
  const booth = getBoothData(uw);
3✔
69
  const waitlist = uw.waitlist.getUserIDs();
3✔
70
  const waitlistLocked = uw.waitlist.isLocked();
3✔
71
  let activePlaylist = user?.activePlaylistID
3✔
72
    ? uw.playlists.getUserPlaylist(user, user.activePlaylistID).catch((error) => {
3✔
NEW
73
      // If the playlist was not found, our database is inconsistent. A deleted or nonexistent
×
NEW
74
      // playlist should never be listed as the active playlist. Most likely this is not the
×
NEW
75
      // user's fault, so we should not error out on `/api/now`. Instead, pretend they don't have
×
NEW
76
      // an active playlist at all. Clients can then let them select a new playlist to activate.
×
NEW
77
      if (error.code === 'NOT_FOUND' || error.code === 'playlist-not-found') {
×
NEW
78
        req.log.warn('The active playlist does not exist', { error });
×
NEW
79
        return null;
×
NEW
80
      }
×
NEW
81
      throw error;
×
82
    })
1✔
83
    : Promise.resolve(null);
3✔
84
  const playlists = user ? uw.playlists.getUserPlaylists(user) : null;
3✔
85
  const firstActivePlaylistItem = activePlaylist.then((playlist) => playlist ? getFirstItem(uw, playlist) : null);
3✔
86
  const socketToken = user ? authRegistry.createAuthToken(user) : null;
3✔
87
  const authStrategies = passport.strategies();
3✔
88
  const time = Date.now();
3✔
89

3✔
90
  const stateShape = {
3✔
91
    motd,
3✔
92
    user: user ? serializeUser(user) : null,
3✔
93
    users,
3✔
94
    guests,
3✔
95
    roles,
3✔
96
    booth,
3✔
97
    waitlist,
3✔
98
    waitlistLocked,
3✔
99
    activePlaylist: activePlaylist.then((playlist) => playlist?.id ?? null),
3✔
100
    firstActivePlaylistItem,
3✔
101
    playlists,
3✔
102
    socketToken,
3✔
103
    authStrategies,
3✔
104
    time,
3✔
105
  };
3✔
106

3✔
107
  const stateKeys = Object.keys(stateShape);
3✔
108
  // This is a little dirty but maintaining the exact type shape is very hard here.
3✔
109
  // We could solve that in the future by using a `p-props` style function. The npm
3✔
110
  // module `p-props` is a bit wasteful though.
3✔
111
  /** @type {any} */
3✔
112
  const values = Object.values(stateShape);
3✔
113
  const stateValues = await Promise.all(values);
3✔
114

3✔
115
  const state = Object.create(null);
3✔
116
  for (let i = 0; i < stateKeys.length; i += 1) {
3✔
117
    state[stateKeys[i]] = stateValues[i];
42✔
118
  }
42✔
119

3✔
120
  if (state.playlists) {
3✔
121
    state.playlists = state.playlists.map(serializePlaylist);
2✔
122
  }
2✔
123

3✔
124
  return state;
3✔
125
}
3✔
126

1✔
127
export { getState };
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc