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

suculent / thinx-device-api / #252646157

09 May 2025 01:17PM UTC coverage: 71.943% (-0.03%) from 71.97%
#252646157

push

suculent
fixed Google login issue; improved logging

1832 of 3470 branches covered (52.8%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

40 existing lines in 3 files now uncovered.

8186 of 10455 relevant lines covered (78.3%)

7.49 hits per line

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

65.38
/lib/thinx/gdpr.js
1
// GDPR
2

3
const Globals = require("./globals.js");
1✔
4
const app_config = Globals.app_config(); // for strict_gdpr
1✔
5

6
module.exports = class GDPR {
1✔
7

8
    constructor(app) {
9
        const Database = require("./database.js");
16✔
10
        let db_uri = new Database().uri();
16✔
11
        this.userlib = require("nano")(db_uri).use(Globals.prefix() + "managed_users");
16✔
12
        this.schedule = require('node-schedule');
16✔
13
        this.owner = app.owner;
16✔
14
    }
15

16
    guard() {
17

18
        if ((typeof (app_config.strict_gdpr) === "undefined") || app_config.strict_gdpr === false) {
16!
19
            return true;
×
20
        }
21

22
        let cron_rule_15_min = "*/15 * * * *";
16✔
23
        let cron_rule_daily = "0 8 * * *"; // daily 8 am
16✔
24

25
        if (process.env.ENVIRONMENT == "test") {
16!
26
            cron_rule_15_min = "0/59 * * * * *"; // seconds
16✔
27
            cron_rule_daily = "0/59 * * * * *"; // seconds
16✔
28
        }
29
    
30
        this.schedule.scheduleJob(cron_rule_15_min, () => {
16✔
UNCOV
31
            this.purgeOldUsers();
×
32
        });
33

34
        
35
        this.schedule.scheduleJob(cron_rule_daily, () => {
16✔
UNCOV
36
            this.notifyOldUsers();
×
37
        });
38
        return true;
16✔
39
    }
40

41
    purgeIfExpired(id) {
42
        var d = new Date();
1✔
43
        d.setMonth(d.getMonth() - 3);
1✔
44
        this.userlib.atomic("users", "delete_expired", id, { mindate: d }, (error, response) => {
1✔
45
            if (error) {
1!
46
                if ((typeof(error.code) !== "undefined") && (error.code !== 409)) console.log("☣️ [error] Purge Old Error:", error, "with id", id); // returns invalid parameters
1!
47
                return;
1✔
48
            } 
49
            console.log("✅ [info] Purged:", response);
×
50
        });
51
    }
52

53
    purgeOldUsers(opt_callback) {
54
        this.userlib.view("users", "owners_by_id", {
1✔
55
                        "include_docs": false
56
        }).then((body) => {
57
            for (let index in body.rows) {
1✔
58
                                let doc = body.rows[index];
1✔
59
                if ((typeof(doc.deleted) === "undefined") || (doc.deleted === false)) {
1!
60
                    this.purgeIfExpired(doc.id);
1✔
61
                }
62
                        }
63
            if (typeof(opt_callback) !== "undefined") opt_callback(true);
1!
64
        }).catch(() => {
65
            if (typeof(opt_callback) !== "undefined") opt_callback(true);   
×
66
        });
67
    }
68

69
    monthDayAgo(month, day) {
70
        var d = new Date();
4✔
71
        d.setMonth(d.getMonth() - month);
4✔
72
        d.setDate(d.getDay() - day);
4✔
73
        return Math.floor(d.valueOf() / 1000);
4✔
74
    }
75

76
    notify24(user, _opt_callback) {
77
        let opt_callback = _opt_callback;
2✔
78
        if ((user.last_update < this.monthDayAgo(3, 1)) &&
2!
79
            ((typeof (user.notifiedBeforeGDPRRemoval24) === "undefined") || (user.notifiedBeforeGDPRRemoval24 !== true))
80
            ) {
81
            this.owner.sendGDPRExpirationEmail24(user, user.email, () => {
×
82
                this.userlib.atomic("users", "edit", user.owner, { notifiedBeforeGDPRRemoval24: true }, (uerror) => {
×
83
                    opt_callback(uerror);
×
84
                    opt_callback = null; // to prevent double call
×
85
                });
86
            });
87
        } else {
88
            if ((typeof (opt_callback) !== "undefined") && (opt_callback !== null)) return opt_callback(false);
2✔
89
        }
90
    }
91

92
    notify168(user, _opt_callback) {
93
        let opt_callback = _opt_callback;
2✔
94
        if ((user.last_update < this.monthDayAgo(3, 7)) &&
2!
95
            ((typeof (user.notifiedBeforeGDPRRemoval168) === "undefined") || (user.notifiedBeforeGDPRRemoval168 !== true))
96
            ) {
97
            this.owner.sendGDPRExpirationEmail168(user, user.email, () => {
×
98
                this.userlib.atomic("users", "edit", user.owner, { notifiedBeforeGDPRRemoval168: true }, (uerror) => {
×
99
                    if (typeof (opt_callback) !== "undefined") {
×
100
                        opt_callback(uerror);
×
101
                        opt_callback = null; // to prevent double call
×
102
                    }
103
                });
104
            });
105
        } else {
106
            if ((typeof (opt_callback) !== "undefined") && (opt_callback !== null)) return opt_callback(false);
2✔
107
        }
108
    }
109

110
    // Should send an e-mails once a day, two emails in total per owner
111
    // Must parse all users, find users with expiration
112
    notifyOldUsers(opt_callback) {
113
        this.userlib.view("users", "owners_by_username", {
1✔
114
            "include_docs": true
115
        }).then((user_view_body) => {
116
            for (var index in user_view_body.rows) {
1✔
117
                let user = user_view_body.rows[index];
1✔
118
                this.notify24(user);
1✔
119
                this.notify168(user);
1✔
120
            }
121
            if (typeof(opt_callback) !== "undefined") opt_callback(true);
1!
122
        }).catch(() => {
123
            if (typeof(opt_callback) !== "undefined") opt_callback(true);
×
124
        });
125
    }
126
};
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