mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-07-02 20:32:58 +00:00
feat(user): persist personalization.location with updateUserLocation
This commit is contained in:
parent
955674db44
commit
72c8eb512f
4 changed files with 88 additions and 1 deletions
|
|
@ -1,9 +1,9 @@
|
|||
import mongoose from 'mongoose';
|
||||
import { MongoMemoryServer } from 'mongodb-memory-server';
|
||||
import type * as t from '~/types';
|
||||
import balanceSchema from '~/schema/balance';
|
||||
import { createUserMethods } from './user';
|
||||
import userSchema from '~/schema/user';
|
||||
import balanceSchema from '~/schema/balance';
|
||||
|
||||
/** Mocking crypto for generateToken */
|
||||
jest.mock('~/crypto', () => ({
|
||||
|
|
@ -694,6 +694,41 @@ describe('User Methods - Database Tests', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('updateUserLocation', () => {
|
||||
it('persists a manual location on a user with no personalization object', async () => {
|
||||
const user = await mongoose.models.User.create({ email: 'loc1@test.com' });
|
||||
const updated = await methods.updateUserLocation(user._id.toString(), {
|
||||
enabled: true,
|
||||
source: 'manual',
|
||||
manual: 'Berlin, Germany',
|
||||
timezone: 'Europe/Berlin',
|
||||
});
|
||||
expect(updated?.personalization?.location?.enabled).toBe(true);
|
||||
expect(updated?.personalization?.location?.manual).toBe('Berlin, Germany');
|
||||
expect(updated?.personalization?.location?.timezone).toBe('Europe/Berlin');
|
||||
});
|
||||
|
||||
it('persists device coordinates and place', async () => {
|
||||
const user = await mongoose.models.User.create({ email: 'loc2@test.com' });
|
||||
const updated = await methods.updateUserLocation(user._id.toString(), {
|
||||
enabled: true,
|
||||
source: 'auto',
|
||||
place: 'Paris, Île-de-France, France',
|
||||
coordinates: { latitude: 48.85, longitude: 2.35 },
|
||||
timezone: 'Europe/Paris',
|
||||
});
|
||||
expect(updated?.personalization?.location?.place).toBe('Paris, Île-de-France, France');
|
||||
expect(updated?.personalization?.location?.coordinates?.latitude).toBe(48.85);
|
||||
});
|
||||
|
||||
it('returns null for a missing user', async () => {
|
||||
const result = await methods.updateUserLocation(new mongoose.Types.ObjectId().toString(), {
|
||||
enabled: false,
|
||||
});
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('findUsers with options', () => {
|
||||
beforeEach(async () => {
|
||||
await User.create([
|
||||
|
|
|
|||
|
|
@ -106,6 +106,10 @@ export function createUserMethods(mongoose: typeof import('mongoose')): {
|
|||
action: 'install' | 'uninstall',
|
||||
) => Promise<IUser | null>;
|
||||
toggleUserMemories: (userId: string, memoriesEnabled: boolean) => Promise<IUser | null>;
|
||||
updateUserLocation: (
|
||||
userId: string,
|
||||
location: import('librechat-data-provider').TUserLocation,
|
||||
) => Promise<IUser | null>;
|
||||
} {
|
||||
/**
|
||||
* Normalizes email fields in search criteria to lowercase and trimmed.
|
||||
|
|
@ -338,6 +342,33 @@ export function createUserMethods(mongoose: typeof import('mongoose')): {
|
|||
}).lean<IUser>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user's location personalization setting.
|
||||
* Creates the personalization object if it doesn't exist.
|
||||
*/
|
||||
async function updateUserLocation(
|
||||
userId: string,
|
||||
location: import('librechat-data-provider').TUserLocation,
|
||||
): Promise<IUser | null> {
|
||||
const User = mongoose.models.User;
|
||||
|
||||
const user = await User.findById(userId);
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const updateOperation = {
|
||||
$set: {
|
||||
'personalization.location': { ...location, updatedAt: new Date() },
|
||||
},
|
||||
};
|
||||
|
||||
return await User.findByIdAndUpdate(userId, updateOperation, {
|
||||
new: true,
|
||||
runValidators: true,
|
||||
}).lean<IUser>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for users by pattern matching on name, email, or username (case-insensitive)
|
||||
* @param searchPattern - The pattern to search for
|
||||
|
|
@ -517,6 +548,7 @@ export function createUserMethods(mongoose: typeof import('mongoose')): {
|
|||
deleteUserById,
|
||||
updateUserPlugins,
|
||||
toggleUserMemories,
|
||||
updateUserLocation,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -133,6 +133,24 @@ const userSchema: Schema<IUser> = new Schema<IUser>(
|
|||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
location: {
|
||||
type: {
|
||||
enabled: { type: Boolean, default: false },
|
||||
source: { type: String, enum: ['auto', 'manual'] },
|
||||
manual: { type: String, maxlength: 256 },
|
||||
place: { type: String, maxlength: 256 },
|
||||
coordinates: {
|
||||
type: {
|
||||
latitude: { type: Number },
|
||||
longitude: { type: Number },
|
||||
},
|
||||
default: undefined,
|
||||
},
|
||||
timezone: { type: String, maxlength: 64 },
|
||||
updatedAt: { type: Date },
|
||||
},
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
default: {},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ export interface IUser extends Document {
|
|||
termsAccepted?: boolean;
|
||||
personalization?: {
|
||||
memories?: boolean;
|
||||
location?: import('librechat-data-provider').TUserLocation;
|
||||
};
|
||||
favorites?: TUserFavorite[];
|
||||
/** Per-skill active/inactive overrides. Key = skillId, value = active state. */
|
||||
|
|
@ -95,6 +96,7 @@ export interface UpdateUserRequest {
|
|||
termsAccepted?: boolean;
|
||||
personalization?: {
|
||||
memories?: boolean;
|
||||
location?: import('librechat-data-provider').TUserLocation;
|
||||
};
|
||||
skillStates?: Record<string, boolean>;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue