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

bpatrik / pigallery2 / 17685697493

12 Sep 2025 08:48PM UTC coverage: 65.828% (+1.7%) from 64.102%
17685697493

push

github

web-flow
Merge pull request #1030 from bpatrik/db-projection

Implement projected (scoped/filtered) gallery. Fixes #1015

1305 of 2243 branches covered (58.18%)

Branch coverage included in aggregate %.

706 of 873 new or added lines in 54 files covered. (80.87%)

16 existing lines in 10 files now uncovered.

4794 of 7022 relevant lines covered (68.27%)

4355.01 hits per line

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

85.07
/src/backend/model/database/SessionManager.ts
1
import * as crypto from 'crypto';
1✔
2
import {ContextUser, SessionContext} from '../SessionContext';
1✔
3
import {SearchQueryUtils} from '../../../common/SearchQueryUtils';
1✔
4
import {Config} from '../../../common/config/private/Config';
1✔
5
import {ANDSearchQuery, SearchQueryDTO, SearchQueryTypes} from '../../../common/entities/SearchQueryDTO';
1✔
6
import {SharingEntity} from './enitites/SharingEntity';
7
import {ObjectManagers} from '../ObjectManagers';
1✔
8
import {Logger} from '../../Logger';
1✔
9

10
const LOG_TAG = '[SessionManager]';
1✔
11

12
export class SessionManager {
1✔
13

14
  public static readonly NO_PROJECTION_KEY = 'pr:' + crypto.createHash('md5').update('No Key').digest('hex');
1✔
15

16
  private getQueryForUser(user: ContextUser) {
17
    let blockQuery = user.overrideAllowBlockList ? user.blockQuery : Config.Users.blockQuery;
362✔
18
    const allowQuery = user.overrideAllowBlockList ? user.allowQuery : Config.Users.allowQuery;
362✔
19

20
    if (SearchQueryUtils.isQueryEmpty(allowQuery) && SearchQueryUtils.isQueryEmpty(blockQuery)) {
362✔
21
      return null;
299✔
22
    }
23

24
    if (!SearchQueryUtils.isQueryEmpty(blockQuery)) {
63✔
25
      blockQuery = SearchQueryUtils.negate(blockQuery);
8✔
26
    }
27
    let query = !SearchQueryUtils.isQueryEmpty(allowQuery) ? allowQuery : blockQuery;
63✔
28
    if (!SearchQueryUtils.isQueryEmpty(allowQuery) && !SearchQueryUtils.isQueryEmpty(blockQuery)) {
63✔
29
      query = {
4✔
30
        type: SearchQueryTypes.AND,
31
        list: [
32
          allowQuery,
33
          blockQuery
34
        ]
35
      } as ANDSearchQuery;
36
    }
37
    return query;
63✔
38

39
  }
40

41
  public buildAllowListForSharing(sharing: SharingEntity): SearchQueryDTO {
42
    const creatorQuery = this.getQueryForUser(sharing.creator);
16✔
43
    let finalQuery = sharing.searchQuery;
16✔
44
    if (creatorQuery) {
16✔
45
      finalQuery = {
4✔
46
        type: SearchQueryTypes.AND,
47
        list: [
48
          creatorQuery,
49
          sharing.searchQuery
50
        ]
51
      } as ANDSearchQuery;
52
    }
53
    return finalQuery;
16✔
54
  }
55

56
  public createProjectionKey(q: SearchQueryDTO) {
57
    const canonical = SearchQueryUtils.stringifyForComparison(q);
64✔
58
    return 'pr:' + crypto.createHash('md5').update(canonical).digest('hex');
64✔
59
  }
60

61
  public async buildContext(user: ContextUser): Promise<SessionContext> {
62
    const context = new SessionContext();
346✔
63
    context.user = user;
346✔
64
    context.user.projectionKey = SessionManager.NO_PROJECTION_KEY;
346✔
65
    let finalQuery = this.getQueryForUser(user);
346✔
66

67
    if (finalQuery) {
346✔
68
      // Build the Brackets-based query
69
      context.projectionQuery = await ObjectManagers.getInstance().SearchManager.prepareAndBuildWhereQuery(finalQuery);
59✔
70
      context.hasDirectoryProjection = ObjectManagers.getInstance().SearchManager.hasDirectoryQuery(finalQuery);
59✔
71
      if (context.hasDirectoryProjection) {
59✔
72
        context.projectionQueryForSubDir = await ObjectManagers.getInstance().SearchManager.prepareAndBuildWhereQuery(finalQuery, true, {directory: 'directories'});
21✔
73
      }
74
      context.user.projectionKey = this.createProjectionKey(finalQuery);
59✔
75
      if (SearchQueryUtils.isQueryEmpty(finalQuery)) {
59!
NEW
76
        Logger.silly(LOG_TAG, 'Empty Projection query.');
×
77
      } else {
78
        Logger.silly(LOG_TAG, 'Projection query: ' + JSON.stringify(finalQuery));
59✔
79
      }
80
    }
81
    return context;
346✔
82
  }
83

84
  async getAvailableUserSessions(): Promise<SessionContext[]> {
85
    // List all users and build a session context for each
NEW
86
    const users = await ObjectManagers.getInstance().UserManager.find({} as any);
×
NEW
87
    const sessions: SessionContext[] = [];
×
NEW
88
    for (const u of users as unknown as ContextUser[]) {
×
NEW
89
      try {
×
NEW
90
        const ctx = await this.buildContext(u);
×
NEW
91
        sessions.push(ctx);
×
92
      } catch (e) {
93
        // Log and continue on individual user context build failure to ensure we return other sessions
NEW
94
        Logger.warn(LOG_TAG, 'Failed to build session context for user id=' + (u as any)?.id + ': ' + (e as Error)?.message);
×
95
      }
96
    }
NEW
97
    return sessions;
×
98
  }
99
}
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