feat: added last login column & about column to user model

This commit is contained in:
Sergey Yarkov 2022-02-02 17:14:52 +03:00
parent 7e81d7b4ff
commit a0cba27c48
9 changed files with 105 additions and 0 deletions

View File

@ -12,6 +12,7 @@ import MeService from 'App/Services/MeService';
*/
import ChangePasswordValidator from 'App/Validators/Password/ChangePasswordValidator';
import UpdateContactsValidator from 'App/Validators/Contacts/UpdateContactsValidator';
import UpdateUserInfoValidator from 'App/Validators/User/UpdateUserInfoValidator';
import BaseController from '../../BaseController';
@ -108,6 +109,21 @@ export default class MeController extends BaseController {
return this.sendResponse(ctx, result.data, result.message, result.status);
}
/**
* Update personal info of user
* PATCH /me/info
*/
public async updateInfo(ctx: HttpContextContract) {
const payload = await ctx.request.validate(UpdateUserInfoValidator);
const result = await this.meService.updateUserInfo(payload, ctx.auth);
if (!result.success && result.error) {
throw new Exception(result.message, result.status, result.error.code);
}
return this.sendResponse(ctx, result.data, result.message, result.status);
}
}
new Ioc().make(MeController);

View File

@ -70,6 +70,12 @@ export default class User extends BaseModel {
})
public lessons_progress: HasMany<typeof LessonProgress>;
@column()
public about: string | null;
@column.dateTime()
public last_login: DateTime | null;
@column.dateTime({ autoCreate: true })
public createdAt: DateTime;

View File

@ -1,4 +1,5 @@
import Hash from '@ioc:Adonis/Core/Hash';
import { DateTime } from 'luxon';
/**
* Models
@ -11,6 +12,7 @@ import Role from 'App/Models/Role';
*/
import CreateUserValidator from 'App/Validators/User/CreateUserValidator';
import UpdateUserValidator from 'App/Validators/User/UpdateUserValidator';
import UpdateUserInfoValidator from 'App/Validators/User/UpdateUserInfoValidator';
export default class UserRepository {
private User: typeof User;
@ -159,6 +161,31 @@ export default class UserRepository {
return null;
}
/**
* Updates the time of last login column in database for user
*
* @param id User id
*/
public async updateLastLogin(id: number | string) {
await this.User.query().where('id', id).update({ last_login: DateTime.now() }).first();
}
/**
* Update personal info of user
*
* @param data New fields
*/
public async updateInfo(id: string | number, data: UpdateUserInfoValidator['schema']['props']) {
const user = await this.User.query().preload('contacts').preload('roles').where('id', id).first();
if (user) {
await user.merge(data).save();
return { about: user.about };
}
return null;
}
/**
* Rewrite all user roles
*

View File

@ -70,8 +70,16 @@ export default class AuthService {
userName: user.fullname,
});
/**
* Set cookie toke to response
*/
ctx.response.cookie('token', token.token);
/**
* Save last login date
*/
await this.userRepository.updateLastLogin(user.id);
return {
success: true,
status: HttpStatusEnum.OK,

View File

@ -13,6 +13,7 @@ import UpdateContactsValidator from 'App/Validators/Contacts/UpdateContactsValid
import CodeErrorEnum from 'App/Datatypes/Enums/CodeErrorEnum';
import RoleHelper from 'App/Helpers/RoleHelper';
import RoleEnum from 'App/Datatypes/Enums/RoleEnum';
import UpdateUserInfoValidator from 'App/Validators/User/UpdateUserInfoValidator';
@inject()
export default class MeService {
@ -279,6 +280,37 @@ export default class MeService {
data: user.contacts,
};
}
public async updateUserInfo(
data: UpdateUserInfoValidator['schema']['props'],
auth: AuthContract
): Promise<IResponse> {
const user = await auth.use(this.authGuard).authenticate();
const info = await this.userRepository.updateInfo(user.id, data);
if (info) {
const { about } = info;
return {
success: true,
status: HttpStatusEnum.OK,
message: 'User info updated.',
data: {
about,
},
};
}
return {
success: false,
status: HttpStatusEnum.SERVICE_UNAVAILABLE,
message: 'Cannot update personal info.',
data: {},
error: {
code: 'E_SERVICE_UNAVAILABLE',
},
};
}
}
new Ioc().make(MeService);

View File

@ -0,0 +1,12 @@
import { schema } from '@ioc:Adonis/Core/Validator';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
export default class UpdateUserInfoValidator {
constructor(protected ctx: HttpContextContract) {}
public schema = schema.create({
about: schema.string.optional(),
});
public messages = {};
}

View File

@ -8,6 +8,7 @@ export default class UpdateUserValidator {
public schema = schema.create({
first_name: schema.string.optional(),
last_name: schema.string.optional(),
about: schema.string.optional(),
login: schema.string.optional({}, [rules.unique({ table: 'users', column: 'login' })]),
email: schema.string.optional({}, [rules.email(), rules.unique({ table: 'users', column: 'email' })]),
password: schema.string.optional(),

View File

@ -8,9 +8,11 @@ export default class Users extends BaseSchema {
table.string('id', 21).primary();
table.string('first_name', 24).notNullable();
table.string('last_name', 24).notNullable();
table.text('about');
table.string('login', 128).notNullable().unique();
table.string('email').notNullable().unique();
table.string('password').notNullable();
table.timestamp('last_login', { useTz: true });
table.timestamp('created_at', { useTz: true });
table.timestamp('updated_at', { useTz: true });
});

View File

@ -2,6 +2,7 @@ import Route from '@ioc:Adonis/Core/Route';
Route.group(() => {
Route.get('/', 'Api/v1/MeController.show').middleware('role:admin,teacher,student').as('me.show');
Route.patch('/info', 'Api/v1/MeController.updateInfo').middleware('role:admin,teacher,student').as('me.update-info');
Route.patch('/email', 'Api/v1/MeController.changeEmail')
.middleware('role:admin,teacher,student')
.as('me.change-email');