feat: implement user authentication with login and register
- Add login screen with email/username support - Add register screen with email validation - Implement AuthStore with expo-secure-store (native) / localStorage (web) - Add X-User-Id header authentication (simple auth without JWT) - Rename displayName to userName across codebase - Add findByUserName() to UserRepository - Check for existing email AND username on registration - Add AuthButton component with shadow effect - Add logout button to Header - Add hash-password.js utility script for manual password resets - Update CORS to allow X-User-Id header
This commit is contained in:
@@ -1,23 +1,38 @@
|
||||
import { User } from "@caldav/shared";
|
||||
import { UserRepository, CreateUserData } from "../../services/interfaces";
|
||||
import { Logged } from "../../logging";
|
||||
import { UserModel } from "./models";
|
||||
import { UserModel, UserDocument } from "./models";
|
||||
|
||||
function toUser(doc: UserDocument): User {
|
||||
return {
|
||||
id: doc._id.toString(),
|
||||
email: doc.email,
|
||||
userName: doc.userName,
|
||||
passwordHash: doc.passwordHash,
|
||||
createdAt: doc.createdAt,
|
||||
updatedAt: doc.updatedAt,
|
||||
};
|
||||
}
|
||||
|
||||
@Logged("MongoUserRepository")
|
||||
export class MongoUserRepository implements UserRepository {
|
||||
async findById(id: string): Promise<User | null> {
|
||||
throw new Error("Not implemented");
|
||||
const user = await UserModel.findById(id);
|
||||
return user ? toUser(user) : null;
|
||||
}
|
||||
|
||||
async findByEmail(email: string): Promise<User | null> {
|
||||
const user = await UserModel.findOne({ email: email.toLowerCase() });
|
||||
// NOTE: Casting required because Mongoose's toJSON() type doesn't reflect our virtual 'id' field
|
||||
return (user?.toJSON() as unknown as User) ?? null;
|
||||
return user ? toUser(user) : null;
|
||||
}
|
||||
|
||||
async findByUserName(userName: string): Promise<User | null> {
|
||||
const user = await UserModel.findOne({ userName });
|
||||
return user ? toUser(user) : null;
|
||||
}
|
||||
|
||||
async create(data: CreateUserData): Promise<User> {
|
||||
const user = await UserModel.create(data);
|
||||
// NOTE: Casting required because Mongoose's toJSON() type doesn't reflect our virtual 'id' field
|
||||
return user.toJSON() as unknown as User;
|
||||
return toUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ const UserSchema = new Schema<
|
||||
lowercase: true,
|
||||
trim: true,
|
||||
},
|
||||
displayName: {
|
||||
userName: {
|
||||
type: String,
|
||||
required: true,
|
||||
trim: true,
|
||||
|
||||
Reference in New Issue
Block a user