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

GEWIS / sudosos-backend / 21215602654

21 Jan 2026 03:23PM UTC coverage: 89.601% (-0.03%) from 89.629%
21215602654

push

github

web-flow
feat: add last seen tracking to users (#709)

1686 of 2034 branches covered (82.89%)

Branch coverage included in aggregate %.

8 of 8 new or added lines in 3 files covered. (100.0%)

25 existing lines in 4 files now uncovered.

8705 of 9563 relevant lines covered (91.03%)

1011.84 hits per line

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

93.68
/src/database/database.ts
1
/**
2
 *  SudoSOS back-end API service.
3
 *  Copyright (C) 2026 Study association GEWIS
4
 *
5
 *  This program is free software: you can redistribute it and/or modify
6
 *  it under the terms of the GNU Affero General Public License as published
7
 *  by the Free Software Foundation, either version 3 of the License, or
8
 *  (at your option) any later version.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU Affero General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU Affero General Public License
16
 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
17
 *
18
 *  @license
19
 */
20

21
/**
22
 * This is the module page of the database.
23
 *
24
 * @module internal/database
25
 */
26

27
import {
2✔
28
  DataSource,
29
} from 'typeorm';
30
import fs from 'fs';
2✔
31
import User from '../entity/user/user';
2✔
32
import Product from '../entity/product/product';
2✔
33
import SubTransaction from '../entity/transactions/sub-transaction';
2✔
34
import Transaction from '../entity/transactions/transaction';
2✔
35
import ProductCategory from '../entity/product/product-category';
2✔
36
import SubTransactionRow from '../entity/transactions/sub-transaction-row';
2✔
37
import PointOfSale from '../entity/point-of-sale/point-of-sale';
2✔
38
import Container from '../entity/container/container';
2✔
39
import VoucherGroup from '../entity/user/voucher-group';
2✔
40
import LocalUser from '../entity/user/local-user';
2✔
41
import MemberUser from '../entity/user/member-user';
2✔
42
import UserVoucherGroup from '../entity/user/user-voucher-group';
2✔
43
import EanAuthenticator from '../entity/authenticator/ean-authenticator';
2✔
44
import OrganMembership from '../entity/organ/organ-membership';
2✔
45
import NfcAuthenticator from '../entity/authenticator/nfc-authenticator';
2✔
46
import PinAuthenticator from '../entity/authenticator/pin-authenticator';
2✔
47
import Banner from '../entity/banner';
2✔
48
import Transfer from '../entity/transactions/transfer';
2✔
49
import ProductRevision from '../entity/product/product-revision';
2✔
50
import ContainerRevision from '../entity/container/container-revision';
2✔
51
import PointOfSaleRevision from '../entity/point-of-sale/point-of-sale-revision';
2✔
52
import ProductOrdering from '../entity/point-of-sale/product-ordering';
2✔
53
import Balance from '../entity/transactions/balance';
2✔
54
import InvoiceUser from '../entity/user/invoice-user';
2✔
55
import Invoice from '../entity/invoices/invoice';
2✔
56
import InvoiceStatus from '../entity/invoices/invoice-status';
2✔
57
import BaseFile from '../entity/file/base-file';
2✔
58
import ProductImage from '../entity/file/product-image';
2✔
59
import BannerImage from '../entity/file/banner-image';
2✔
60
import StripeDeposit from '../entity/stripe/stripe-deposit';
2✔
61
import StripePaymentIntentStatus from '../entity/stripe/stripe-payment-intent-status';
2✔
62
import PayoutRequest from '../entity/transactions/payout/payout-request';
2✔
63
import PayoutRequestStatus from '../entity/transactions/payout/payout-request-status';
2✔
64
import LDAPAuthenticator from '../entity/authenticator/ldap-authenticator';
2✔
65
import AssignedRole from '../entity/rbac/assigned-role';
2✔
66
import VatGroup from '../entity/vat-group';
2✔
67
import LocalAuthenticator from '../entity/authenticator/local-authenticator';
2✔
68
import ResetToken from '../entity/authenticator/reset-token';
2✔
69
import { DataSourceOptions } from 'typeorm/data-source/DataSourceOptions';
70
import KeyAuthenticator from '../entity/authenticator/key-authenticator';
2✔
71
import Fine from '../entity/fine/fine';
2✔
72
import FineHandoutEvent from '../entity/fine/fineHandoutEvent';
2✔
73
import UserFineGroup from '../entity/fine/userFineGroup';
2✔
74
import Event from '../entity/event/event';
2✔
75
import EventShiftAnswer from '../entity/event/event-shift-answer';
2✔
76
import EventShift from '../entity/event/event-shift';
2✔
77
import { TransactionSubscriber, TransferSubscriber } from '../subscriber';
2✔
78
import InvoicePdf from '../entity/file/invoice-pdf';
2✔
79
import dotenv from 'dotenv';
2✔
80
import PayoutRequestPdf from '../entity/file/payout-request-pdf';
2✔
81
import Role from '../entity/rbac/role';
2✔
82
import Permission from '../entity/rbac/permission';
2✔
83
import RoleUserType from '../entity/rbac/role-user-type';
2✔
84
import WriteOff from '../entity/transactions/write-off';
2✔
85
import ServerSetting from '../entity/server-setting';
2✔
86
import StripePaymentIntent from '../entity/stripe/stripe-payment-intent';
2✔
87
import SellerPayout from '../entity/transactions/payout/seller-payout';
2✔
88
import SellerPayoutPdf from '../entity/file/seller-payout-pdf';
2✔
89
import { InitialSQLMigration1743601882766 } from '../migrations/1743601882766-initial-database';
2✔
90
import WriteOffPdf from '../entity/file/write-off-pdf';
2✔
91
import QRAuthenticator from '../entity/authenticator/qr-authenticator';
2✔
92
import { QrAuthenticator1743601882766 } from '../migrations/1743601882766-qr-authenticator';
2✔
93
import { MemberAuthenticator1761324427011 } from '../migrations/1761324427011-member-authenticator';
2✔
94
import { AddOrganMembershipIndex1761328648026 } from '../migrations/1761328648026-add-organ-membership-index';
2✔
95
import InactiveAdministrativeCost from '../entity/transactions/inactive-administrative-cost';
2✔
96
import {
2✔
97
  UserAdministrativeCost1761845457283,
98
} from '../migrations/1761845457283-user-administrative-cost';
99
import NotificationLog from '../entity/notifications/notification-log';
2✔
100
import UserNotificationPreference from '../entity/notifications/user-notification-preference';
2✔
101
import { RenameGewisToExternal1763399087409 } from '../migrations/1763399087409-rename-gewis-to-external';
2✔
102
import { UserNotificationPreference1764615514906 } from '../migrations/1764615514906-user-notification-preference';
2✔
103
import Wrapped from '../entity/wrapped';
2✔
104
import WrappedOrganMember from '../entity/wrapped/wrapped-organ-member';
2✔
105
import { AddWrappedTable1764842063654 } from '../migrations/1764842063654-add-wrapped-table';
2✔
106
import { AddWrappedOrganMember1765826596888 } from '../migrations/1765826596888-add-wrapped-organ-member';
2✔
107
import UserSetting from '../entity/user-setting';
2✔
108
import { UserSetting1768697568707 } from '../migrations/1768697568707-user-setting';
2✔
109
import {
2✔
110
  RemoveCreditTransferFromInactiveAdministrativeCost1769005123365,
111
} from '../migrations/1769005123365-remove-credit-transfer-from-inactive-administrative-cost';
112
import { AddLastSeenToUser1769000095806 } from '../migrations/1769000095806-add-last-seen-to-user';
2✔
113

114
// We need to load the dotenv to prevent the env from being undefined.
115
dotenv.config();
2✔
116

117
if (process.env.NODE_ENV === 'test') {
2!
UNCOV
118
  console.log('TYPEORM_CONNECTION:', process.env.TYPEORM_CONNECTION);
×
119
}
120

121
const options: DataSourceOptions = {
2✔
122
  host: process.env.TYPEORM_HOST,
123
  port: parseInt(process.env.TYPEORM_PORT || '3001'),
2!
124
  database: process.env.TYPEORM_DATABASE,
125
  type: process.env.TYPEORM_CONNECTION as 'postgres' | 'mariadb' | 'mysql',
126
  username: process.env.TYPEORM_USERNAME,
127
  password: process.env.TYPEORM_PASSWORD,
128
  ...(process.env.TYPEORM_SSL_ENABLED === 'true' ? {
2!
129
    ssl: {
130
      ca: fs.readFileSync(process.env.TYPEORM_SSL_CACERTS),
131
    },
132
  } : {}),
133
  synchronize: process.env.TYPEORM_SYNCHRONIZE === 'true',
134
  logging: process.env.TYPEORM_LOGGING === 'true',
135
  migrations: [
136
    InitialSQLMigration1743601882766,
137
    QrAuthenticator1743601882766,
138
    MemberAuthenticator1761324427011,
139
    AddOrganMembershipIndex1761328648026,
140
    UserAdministrativeCost1761845457283,
141
    RenameGewisToExternal1763399087409,
142
    UserNotificationPreference1764615514906,
143
    AddWrappedTable1764842063654,
144
    AddWrappedOrganMember1765826596888,
145
    UserSetting1768697568707,
146
    RemoveCreditTransferFromInactiveAdministrativeCost1769005123365,
147
    AddLastSeenToUser1769000095806,
148
  ],
149
  extra: {
150
    authPlugins: {
UNCOV
151
      mysql_clear_password: () => () => Buffer.from(`${process.env.TYPEORM_PASSWORD}\0`),
×
152
    },
153
  },
154
  poolSize: 4,
155
  entities: [
156
    ServerSetting,
157
    ProductCategory,
158
    VatGroup,
159
    Product,
160
    ProductRevision,
161
    Container,
162
    ContainerRevision,
163
    PointOfSale,
164
    PointOfSaleRevision,
165
    Transfer,
166
    InactiveAdministrativeCost,
167
    StripeDeposit,
168
    StripePaymentIntent,
169
    StripePaymentIntentStatus,
170
    PayoutRequest,
171
    PayoutRequestPdf,
172
    PayoutRequestStatus,
173
    SellerPayout,
174
    SellerPayoutPdf,
175
    Fine,
176
    FineHandoutEvent,
177
    UserFineGroup,
178
    Transaction,
179
    SubTransaction,
180
    SubTransactionRow,
181
    VoucherGroup,
182
    User,
183
    LocalUser,
184
    MemberUser,
185
    UserVoucherGroup,
186
    EanAuthenticator,
187
    OrganMembership,
188
    NfcAuthenticator,
189
    KeyAuthenticator,
190
    PinAuthenticator,
191
    LocalAuthenticator,
192
    LDAPAuthenticator,
193
    Banner,
194
    ProductOrdering,
195
    Balance,
196
    InvoiceUser,
197
    Invoice,
198
    InvoiceStatus,
199
    InvoicePdf,
200
    BaseFile,
201
    ProductImage,
202
    BannerImage,
203
    Role,
204
    RoleUserType,
205
    Permission,
206
    AssignedRole,
207
    ResetToken,
208
    Event,
209
    EventShift,
210
    EventShiftAnswer,
211
    Wrapped,
212
    WrappedOrganMember,
213
    WriteOff,
214
    WriteOffPdf,
215
    QRAuthenticator,
216
    NotificationLog,
217
    UserNotificationPreference,
218
    UserSetting,
219
  ],
220
  subscribers: [
221
    TransactionSubscriber,
222
    TransferSubscriber,
223
  ],
224
};
225

226
export let AppDataSource = new DataSource(options);
2✔
227

228
const Database = {
2✔
229
  initialize: async () => {
230
    if (AppDataSource.isInitialized) return AppDataSource;
121!
231
    return AppDataSource.initialize();
121✔
232
  },
233
};
234

235
export default Database;
2✔
236

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