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

karanshukla / navyfragen-app / 30026965546

23 Jul 2026 04:52PM UTC coverage: 99.804% (-0.2%) from 100.0%
30026965546

push

github

web-flow
Merge pull request #280 from karanshukla/hotfix/customise-box-sizing

fix(customise): uniform card sizing to match Settings grid

2496 of 2517 branches covered (99.17%)

Branch coverage included in aggregate %.

9744 of 9747 relevant lines covered (99.97%)

8.16 hits per line

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

98.97
/server/src/controllers/settings-controller.ts
1
/* v8 ignore start */
1✔
2
import express from "express";
1✔
3
import { body } from "express-validator";
1✔
4
import { Logger } from "pino";
1✔
5

1✔
6
import { SettingsService } from "../services/settings-service";
1✔
7

1✔
8
import type { AppContext } from "../index";
1✔
9

1✔
10
import { initializeAgentFromSession } from "#/auth/session-agent";
1✔
11

1✔
12
export class SettingsController {
1✔
13
  constructor(
1✔
14
    private settingsService: SettingsService,
1✔
15
    private logger: Logger,
1✔
16
    private ctx: AppContext
1✔
17
  ) {}
1✔
18
  /* v8 ignore stop */
1✔
19

16✔
20
  /**
16✔
21
   * Get the user's settings or create default ones if they don't exist
16✔
22
   */
16✔
23
  getSettings = async (req: express.Request, res: express.Response): Promise<express.Response> => {
16✔
24
    const userSessionDid = req.session?.did;
4✔
25

4✔
26
    if (!userSessionDid) {
4✔
27
      return res.status(403).json({ error: "Not authenticated" });
1✔
28
    }
1✔
29

4✔
30
    try {
4✔
31
      let userSettings = await this.settingsService.getUserSettings(userSessionDid);
3✔
32

4✔
33
      if (!userSettings) {
4✔
34
        // Create default settings if they don't exist
1✔
35
        userSettings = await this.settingsService.createDefaultSettings(userSessionDid);
1✔
36
      }
1✔
37

4✔
38
      return res.json(userSettings);
4✔
39
    } catch (err) {
4✔
40
      this.logger.error({ err, did: userSessionDid }, "Failed to fetch user settings");
1✔
41
      return res.status(500).json({ error: "Failed to fetch user settings" });
1✔
42
    }
1✔
43
  };
4✔
44

16✔
45
  /**
16✔
46
   * Get account stats for the logged-in user
16✔
47
   */
16✔
48
  getStats = async (req: express.Request, res: express.Response): Promise<express.Response> => {
16✔
49
    const userSessionDid = req.session?.did;
3✔
50

3✔
51
    if (!userSessionDid) {
3✔
52
      return res.status(403).json({ error: "Not authenticated" });
1✔
53
    }
1✔
54

3✔
55
    try {
3✔
56
      const stats = await this.settingsService.getStats(userSessionDid);
2✔
57
      return res.json(stats);
3✔
58
    } catch (err) {
1✔
59
      this.logger.error({ err, did: userSessionDid }, "Failed to fetch user stats");
1✔
60
      return res.status(500).json({ error: "Failed to fetch user stats" });
1✔
61
    }
1✔
62
  };
3✔
63

16✔
64
  /**
16✔
65
   * Get PDS URL and navyfragen record count for the logged-in user
16✔
66
   */
16✔
67
  getPdsInfo = async (req: express.Request, res: express.Response): Promise<express.Response> => {
16✔
68
    const userDid = req.session?.did;
4✔
69
    if (!userDid) {
4✔
70
      return res.status(403).json({ error: "Not authenticated" });
1✔
71
    }
1✔
72

4✔
73
    const agent = await initializeAgentFromSession(req, this.ctx);
4✔
74
    if (!agent) {
4✔
75
      return res.status(401).json({ error: "Session expired" });
1✔
76
    }
1✔
77

4✔
78
    try {
4✔
79
      const info = await this.settingsService.getPdsInfo(userDid, agent, this.ctx.idResolver);
2✔
80
      return res.json(info);
4✔
81
    } catch (err) {
1✔
82
      this.logger.error({ err, did: userDid }, "Failed to fetch PDS info");
1✔
83
      return res.status(500).json({ error: "Failed to fetch PDS info" });
1✔
84
    }
1✔
85
  };
4✔
86

16✔
87
  /**
16✔
88
   * Validate request for updating settings.
16✔
89
   *
16✔
90
   * Every field is optional — the /customise page persists one card's setting
16✔
91
   * at a time, so only validate the keys a client actually sent. Null is a
16✔
92
   * valid value for the nullable columns (it means "use the default").
16✔
93
   */
16✔
94
  validateUpdateSettings = [
16✔
95
    body("pdsSyncEnabled")
16✔
96
      .optional()
16✔
97
      .isBoolean()
16✔
98
      .withMessage("pdsSyncEnabled must be a boolean value"),
16✔
99
    body("imageTheme")
16✔
100
      .optional({ nullable: true })
16✔
101
      .isString()
16✔
102
      .withMessage("imageTheme must be a string")
16✔
103
      .notEmpty()
16✔
104
      .withMessage("imageTheme cannot be empty"),
16✔
105
    body("inboxEnabled").optional().isBoolean().withMessage("inboxEnabled must be a boolean value"),
16✔
106
    body("profanityFilterEnabled")
16✔
107
      .optional()
16✔
108
      .isBoolean()
16✔
109
      .withMessage("profanityFilterEnabled must be a boolean value"),
16✔
110
    body("customPrompt")
16✔
111
      .optional({ nullable: true })
16✔
112
      .isString()
16✔
113
      .isLength({ max: 100 })
16✔
114
      .withMessage("customPrompt must be a string of at most 100 chars"),
16✔
115
    body("profileCardTheme")
16✔
116
      .optional({ nullable: true })
16✔
117
      .isString()
16✔
118
      .withMessage("profileCardTheme must be a string"),
16✔
119
    body("touchpointLocale")
16✔
120
      .optional({ nullable: true })
16✔
121
      .isString()
16✔
122
      .withMessage("touchpointLocale must be a string"),
16✔
123
  ];
16✔
124
  /**
16✔
125
   * Update the user's settings
16✔
126
   */
16✔
127
  updateSettings = async (
16✔
128
    req: express.Request,
5✔
129
    res: express.Response
5✔
130
  ): Promise<express.Response> => {
5✔
131
    const userSessionDid = req.session?.did;
5✔
132

5✔
133
    if (!userSessionDid) {
5✔
134
      return res.status(403).json({ error: "Not authenticated" });
1✔
135
    }
1✔
136

5✔
137
    try {
5✔
138
      const updatedSettings = await this.settingsService.updateSettings(userSessionDid, {
4✔
139
        pdsSyncEnabled:
4✔
140
          req.body.pdsSyncEnabled === undefined ? undefined : req.body.pdsSyncEnabled === true,
5✔
141
        imageTheme: req.body.imageTheme,
5✔
142
        inboxEnabled:
5✔
143
          req.body.inboxEnabled === undefined ? undefined : req.body.inboxEnabled === true,
5✔
144
        profanityFilterEnabled:
5✔
145
          req.body.profanityFilterEnabled === undefined
5✔
146
            ? undefined
4!
147
            : req.body.profanityFilterEnabled === true,
×
148
        customPrompt: req.body.customPrompt,
5✔
149
        profileCardTheme: req.body.profileCardTheme,
5✔
150
        touchpointLocale: req.body.touchpointLocale,
5✔
151
      });
5✔
152
      this.logger.info({ did: userSessionDid, updates: req.body }, "Settings updated");
5✔
153
      return res.json(updatedSettings);
3✔
154
    } catch (err) {
5✔
155
      this.logger.error({ err, did: userSessionDid }, "Failed to update user settings");
1✔
156
      return res.status(500).json({ error: "Failed to update user settings" });
1✔
157
    }
1✔
158
  };
5✔
159
  /* v8 ignore next 1 */
1✔
160
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc