Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6d9fb34
eslint: turn off underscore-dangle warning
clairep94 Sep 25, 2025
dd4c6e6
install bcrypt type
clairep94 Sep 25, 2025
f10ae22
server/types: add email confirmation states & user preferences
clairep94 Sep 25, 2025
f56509f
package.json reorder after re-install
clairep94 Sep 26, 2025
2d37b08
server/models: refactor apiKey to its own file & add test
clairep94 Sep 26, 2025
0fc60bd
model/user: add unit test for user model
clairep94 Sep 26, 2025
ae11dc8
migrate to ts, no-verify
clairep94 Sep 26, 2025
17455f5
apiKey: first attempt at defining types --no-verify
clairep94 Sep 26, 2025
fc58c79
apiKey: add working types
clairep94 Sep 26, 2025
3baec8f
apiKey: migrate to separate types file
clairep94 Sep 26, 2025
6bb876f
turn on strict null checks for mongoose infer
clairep94 Sep 26, 2025
8c06deb
models/user: migrate to ts, no-verify
clairep94 Sep 26, 2025
2be814f
models/apiKey: re-implement in pattern from attempt 2 --no-verify
clairep94 Sep 26, 2025
bb61e13
model/user: test update to ts, no-verify
clairep94 Sep 27, 2025
3746446
model/user: update user mock and resolve failing tests, no-verify
clairep94 Sep 27, 2025
000963d
install sinon types, no-verify
clairep94 Sep 27, 2025
5f1efe8
models/user: update to named export, no-verify but tests pass
clairep94 Sep 27, 2025
790ba5b
models/user: resolve types using definitions from attempt 1 PR with t…
clairep94 Sep 27, 2025
0ebbf59
models/user: attach EmailConfirmationStates via function call
clairep94 Sep 27, 2025
9e121fd
cleanup
clairep94 Sep 27, 2025
2d71fc7
update user model test to use mongodb-memory-server for passing on lo…
clairep94 Sep 27, 2025
e453119
nominal change to trigger ci
clairep94 Sep 27, 2025
a713de7
Merge branch 'develop' into pr05/migrate_user_model_finalattempt
clairep94 Sep 27, 2025
23bb85a
merge with develop
Oct 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
models/user: resolve types using definitions from attempt 1 PR with t…
…ests passing
  • Loading branch information
clairep94 committed Sep 27, 2025
commit 790ba5b5fed38f63915214df8831836476fb02be
7 changes: 4 additions & 3 deletions server/models/__test__/user.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ describe('User model', () => {

const found = await User.findByEmail('[email protected]');
expect(found).not.toBeNull();
expect(found.username).toBe('dave');
expect(found!.username).toBe('dave'); // found exists otherwise the previous expect would fail
});

it('should find user by username (case insensitive)', async () => {
Expand All @@ -98,7 +98,7 @@ describe('User model', () => {

const found = await User.findByUsername('eve', { caseInsensitive: true });
expect(found).not.toBeNull();
expect(found.email).toBe('[email protected]');
expect(found!.email).toBe('[email protected]'); // found exists otherwise the previous expect would fail
});

it('should return null for wrong username/email', async () => {
Expand All @@ -115,7 +115,8 @@ describe('User model', () => {
await user.save();

const savedUser = await User.findOne({ email: '[email protected]' });
const keyObj = await savedUser.findMatchingKey('hashedApiKey');
expect(savedUser).not.toBeNull();
const keyObj = await savedUser!.findMatchingKey('hashedApiKey'); // savedUser exists otherwise the previous expect would fail

expect(keyObj.isMatch).toBe(true);
expect(keyObj.keyDocument).not.toBeNull();
Expand Down
2 changes: 1 addition & 1 deletion server/models/apiKey.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Schema } from 'mongoose';
import { SanitisedApiKey, ApiKeyDocument, ApiKeyModel } from '../types/apiKey';
import { SanitisedApiKey, ApiKeyDocument, ApiKeyModel } from '../types';

export const apiKeySchema = new Schema<ApiKeyDocument, ApiKeyModel>(
{
Expand Down
44 changes: 27 additions & 17 deletions server/models/user.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import mongoose from 'mongoose';
import mongoose, { Schema } from 'mongoose';
import bcrypt from 'bcryptjs';
import {
UserDocument,
UserModel,
CookieConsentOptions,
EmailConfirmationStates
} from '../types';
import { apiKeySchema } from './apiKey';

const EmailConfirmationStates = {
Verified: 'verified',
Sent: 'sent',
Resent: 'resent'
};

const { Schema } = mongoose;
// const EmailConfirmationStates = {
// Verified: 'verified',
// Sent: 'sent',
// Resent: 'resent'
// };

const userSchema = new Schema(
const userSchema = new Schema<UserDocument, UserModel>(
{
name: { type: String, default: '' },
username: { type: String, required: true, unique: true },
Expand Down Expand Up @@ -44,13 +48,13 @@ const userSchema = new Schema(
totalSize: { type: Number, default: 0 },
cookieConsent: {
type: String,
enum: ['none', 'essential', 'all'],
default: 'none'
enum: Object.values(CookieConsentOptions),
default: CookieConsentOptions.NONE
},
banned: { type: Boolean, default: false },
lastLoginTimestamp: { type: Date }
},
{ timestamps: true, usePushEach: true }
{ timestamps: true }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't need usePushEach anymore? is it set to that by default? just wanted to make sure it didn't slip through the cracks!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this! It was used for older mongo versions, and is no longer needed past v5, so i think we might be good here!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi guys sorry for the delayed response! Yess once I migrated this file to ts, usePushEach was highlighting in red as it was deprecated for the current version of mongo, so I think we're meant to delete it

);

/**
Expand All @@ -67,6 +71,10 @@ userSchema.pre('save', function checkPassword(next) {
next(err);
return;
}
if (!user.password) {
next(new Error('Password is missing'));
return;
}
bcrypt.hash(user.password, salt, (innerErr, hash) => {
if (innerErr) {
next(innerErr);
Expand All @@ -92,7 +100,7 @@ userSchema.pre('save', function checkApiKey(next) {
let pendingTasks = 0;
let nextCalled = false;

const done = (err) => {
const done = (err?: mongoose.CallbackError) => {
if (nextCalled) return;
if (err) {
nextCalled = true;
Expand Down Expand Up @@ -144,7 +152,7 @@ userSchema.set('toJSON', {
* @return {Promise<boolean>}
*/
userSchema.methods.comparePassword = async function comparePassword(
candidatePassword
candidatePassword: string
) {
if (!this.password) {
return false;
Expand All @@ -162,7 +170,7 @@ userSchema.methods.comparePassword = async function comparePassword(
* Helper method for validating a user's api key
*/
userSchema.methods.findMatchingKey = async function findMatchingKey(
candidateKey
candidateKey: string
) {
let keyObj = { isMatch: false, keyDocument: null };
/* eslint-disable no-restricted-syntax */
Expand Down Expand Up @@ -332,9 +340,11 @@ userSchema.statics.findByEmailAndUsername = async function findByEmailAndUsernam
return foundUser;
};

userSchema.statics.EmailConfirmation = EmailConfirmationStates;
// userSchema.statics.EmailConfirmation = EmailConfirmationStates;

userSchema.index({ username: 1 }, { collation: { locale: 'en', strength: 2 } });
userSchema.index({ email: 1 }, { collation: { locale: 'en', strength: 2 } });

export const User = mongoose.models.User || mongoose.model('User', userSchema);
export const User =
(mongoose.models.User as UserModel) ||
mongoose.model<UserDocument, UserModel>('User', userSchema);
3 changes: 3 additions & 0 deletions server/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
export * from './apiKey';
export * from './email';
export * from './mongoose';
export * from './user';
export * from './userPreferences';
2 changes: 1 addition & 1 deletion server/types/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface IUser {
id: string;
name: string;
username: string;
password?: string;
password: string;
resetPasswordToken?: string;
resetPasswordExpires?: number;
verified?: string;
Expand Down