Skip to content

Commit

Permalink
feat: add user avatars (#1563)
Browse files Browse the repository at this point in the history
Will be used in a new navigation bar.
  • Loading branch information
aalemayhu authored Aug 3, 2024
1 parent 9f51ecf commit 7476caf
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 10 deletions.
11 changes: 11 additions & 0 deletions migrations/20240803100000_user_picture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports.up = (knex) => {
return knex.schema.table('users', (table) => {
table.string('picture').defaultTo(null);
});
};

module.exports.down = (knex) => {
return knex.schema.table('users', (table) => {
table.dropColumn('picture');
});
};
16 changes: 16 additions & 0 deletions migrations/20240803100001_add_missing_user_picture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
exports.up = async function (knex) {
const users = await knex('users').whereNull('picture');

for (const user of users) {
const picture = `https://2anki.net/blue-square.png`;
await knex('users')
.where('id', user.id)
.update({ picture });
}
};

exports.down = async function (knex) {
await knex('users')
.whereNotNull('picture')
.update({ picture: null });
};
28 changes: 25 additions & 3 deletions src/controllers/UsersControllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getRedirect } from './helpers/getRedirect';

import { getIndexFileContents } from './IndexController/getIndexFileContents';
import { getRandomUUID } from '../shared/helpers/getRandomUUID';
import { getDefaultAvatarPicture } from '../lib/getDefaultAvatarPicture';

class UsersController {
constructor(
Expand Down Expand Up @@ -134,7 +135,12 @@ class UsersController {
const password = this.authService.getHashPassword(req.body.password);
const { name, email } = req.body;
try {
await this.userService.register(name, password, email);
await this.userService.register(
name,
password,
email,
getDefaultAvatarPicture()
);
res.status(200).json({ message: 'ok' });
} catch (error) {
sendError(error);
Expand Down Expand Up @@ -246,11 +252,11 @@ class UsersController {
/**
* now create a new user if the user does not exist
*/
const { email, name } = loginRequest;
const { email, name, picture } = loginRequest;
let user = await this.userService.getUserFrom(email);
if (!user) {
// Create user with random password
await this.userService.register(name, getRandomUUID(), email);
await this.userService.register(name, getRandomUUID(), email, picture);
user = await this.userService.getUserFrom(email);
}

Expand All @@ -261,6 +267,10 @@ class UsersController {
.send('Unknown error. Please try again or register a new account.');
}

if (picture != user.picture) {
await this.userService.updatePicture(user.id, picture);
}

const token = await this.authService.newJWTToken(user);
if (!token) {
console.info('Failed to create token');
Expand All @@ -275,6 +285,18 @@ class UsersController {
res.redirect('/login');
}
}

async getAvatar(req: express.Request, res: express.Response) {
if (!res.locals.owner) {
return res.status(400).json({ message: 'Missing owner' });
}

const user = await this.userService.getUserById(res.locals.owner);
const name = user.name;
const picture = user.picture;

return res.json({ name, picture });
}
}

export default UsersController;
7 changes: 6 additions & 1 deletion src/data_layer/UsersRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ class UsersRepository {
.update({ reset_token: resetToken });
}

createUser(name: string, password: string, email: any) {
createUser(name: string, password: string, email: string, picture?: string) {
return this.database(this.table)
.insert({
name,
password,
email,
picture,
})
.returning(['id']);
}
Expand Down Expand Up @@ -95,6 +96,10 @@ class UsersRepository {
.first();
return subscription?.linked_email;
}

updatePicture(id: string, picture: string) {
return this.database(this.table).where({ id }).update({ picture });
}
}

export default UsersRepository;
2 changes: 1 addition & 1 deletion src/data_layer/public/Favorites.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @generated
// This file is automatically generated by Kanel. Do not modify manually.

import { type UsersId } from './Users';
import type { UsersId } from './Users';

/** Represents the table public.favorites */
export default interface Favorites {
Expand Down
7 changes: 7 additions & 0 deletions src/data_layer/public/Users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export default interface Users {
reset_token: string | null;

patreon: boolean | null;

picture: string | null;
}

/** Represents the initializer for the table public.users */
Expand All @@ -44,6 +46,9 @@ export interface UsersInitializer {

/** Default value: false */
patreon?: boolean | null;

/** Default value: NULL::character varying */
picture?: string | null;
}

/** Represents the mutator for the table public.users */
Expand All @@ -63,4 +68,6 @@ export interface UsersMutator {
reset_token?: string | null;

patreon?: boolean | null;

picture?: string | null;
}
3 changes: 3 additions & 0 deletions src/lib/getDefaultAvatarPicture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function getDefaultAvatarPicture() {
return 'https://2anki.net/blue-square.png';
}
4 changes: 4 additions & 0 deletions src/routes/UserRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ const UserRouter = () => {
controller.loginWithGoogle(req, res)
);

router.get('/api/users/avatar', RequireAuthentication, (req, res) =>
controller.getAvatar(req, res)
);

return router;
};

Expand Down
13 changes: 10 additions & 3 deletions src/services/AuthenticationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,16 @@ class AuthenticationService {
});
const idToken = result.data.id_token;
const decoded = jwt.decode(idToken)!;

// @ts-ignore
return { email: decoded.email, name: decoded.name };
console.log('decoded', decoded);

return {
// @ts-ignore
email: decoded.email,
// @ts-ignore
name: decoded.name,
// @ts-ignore
picture: decoded.picture,
};
} catch (error) {
console.info("Couldn't login with Google");
sendError(error);
Expand Down
13 changes: 11 additions & 2 deletions src/services/UsersService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,13 @@ class UsersService {
return this.repository.getByEmail(email);
}

register(name: string, password: string, email: any) {
return this.repository.createUser(name, password, email.toLowerCase());
register(name: string, password: string, email: string, picture: string) {
return this.repository.createUser(
name,
password,
email.toLowerCase(),
picture
);
}

deleteUser(owner: any) {
Expand All @@ -67,6 +72,10 @@ class UsersService {
getUserById(owner: string): Promise<Users> {
return this.repository.getById(owner);
}

updatePicture(id: string, picture: string) {
return this.repository.updatePicture(id, picture);
}
}

export default UsersService;

0 comments on commit 7476caf

Please sign in to comment.