Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/favorite rooms #422

Closed
wants to merge 14 commits into from
29 changes: 29 additions & 0 deletions migrations/20200831005029_create_favorites.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as Knex from 'knex'


export async function up(knex: Knex): Promise<void> {
return knex.schema
.createTable('favorites', table => {
table.increments('id').primary()

table.unique(['userId', 'room'])

table
.integer('userId')
.unsigned()
.references('id')
.inTable('users')
.index()

table
.integer('room')
.notNullable()
})
}


export async function down(knex: Knex): Promise<void> {
return knex.schema
.dropTableIfExists('favorites')
}

15 changes: 15 additions & 0 deletions migrations/20201013213953_remove_floor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as Knex from 'knex'

export async function up(knex: Knex): Promise<void> {
return knex.schema.table('users', table => {
table.dropColumn('floor')
})
}

export async function down(knex: Knex): Promise<void> {
return knex.schema.table('users', table => {
table.integer('floor')
.unsigned()
.nullable()
})
}
8 changes: 8 additions & 0 deletions public/css/additions.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ article.message.alert-detail {
height: 100%;
}

.is-clickable {
cursor: pointer;
}

.flex-column {
display: flex;
flex-direction: column;
Expand All @@ -69,6 +73,10 @@ article.message.alert-detail {
}
}

.is-clickable {
cursor: pointer;
}

// Additional bulma extensions
@import "../../node_modules/bulma-tooltip/src/sass/index.sass";
@import "../../node_modules/@creativebulma/bulma-tagsinput/src/sass/index.sass";
Expand Down
58 changes: 58 additions & 0 deletions public/js/favorite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
OmTheTurtle marked this conversation as resolved.
Show resolved Hide resolved
function deleteFavorite(room) {
fetch(`/favorites/${room}`, {
method: 'DELETE'
})
.then(async res => {
switch (res.status) {
case 201:
location.reload()
break
case 401:
displayMessage('danger', UNAUTHORIZED_MESSAGE)
break
case 403:
displayMessage('danger', FORBIDDEN_MESSAGE)
break
case 404:
data = await res.json()
displayMessage('danger', data.message)
break
}
})
.catch(err => displayMessage('danger', err))
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function addFavorite(room) {
if (!room) {
displayMessage('danger', err)
} else {
fetch('/favorites', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
room
}),
})
.then(async (res) => {
switch (res.status) {
case 201:
location.reload()
break
case 401:
displayMessage('danger', UNAUTHORIZED_MESSAGE)
break
case 403:
displayMessage('danger', FORBIDDEN_MESSAGE)
break
case 404:
data = await res.json()
displayMessage('danger', data.message)
break
}
})
.catch((err) => displayMessage('danger', err))
}
}
2 changes: 1 addition & 1 deletion public/js/ticket.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function addTicket() {
.catch((err) => displayMessage('danger', err))
}
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
function moveTicket(id) {
const formEl = document.getElementById(`ticket-form-${id}`)
const formData = new FormData(formEl)
Expand Down
37 changes: 0 additions & 37 deletions public/js/user.js
Original file line number Diff line number Diff line change
@@ -1,37 +0,0 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function updateUser(id) {
const floorEl = document.getElementById('floor-input')
const floor = parseInt(floorEl.value)
if (floorEl.value !== '' && (floor < 3 || floor > 18)) {
displayMessage('danger', 'A szint üres vagy 3 és 18 közötti szám lehet')
} else {
fetch(`/users/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ floor }),
})
.then(async res => {
switch (res.status) {
case 200:
const user = await res.json()
floorEl.value = user.floor
displayMessage('success', 'Sikeres mentés!')
break
case 400:
const data = await res.json()
clearMessages()
data.errors.forEach(err => displayMessage('danger', err.msg))
break
case 401:
displayMessage('danger', UNAUTHORIZED_MESSAGE)
break
default:
displayMessage('danger', 'Nem várt hiba történt')
break
}
})
.catch((err) => console.error(err))
}
}
3 changes: 3 additions & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { SESSION_SECRET } from './util/secrets'
import userRouter from './components/users/user.routes'
import ticketRouter from './components/tickets/ticket.routes'
import roomRouter, { index } from './components/rooms/room.routes'
import favoriteRouter from './components/favorites/favorite.routes'
import groupRouter from './components/groups/group.routes'

const knex = Knex(dbConfig)
Expand Down Expand Up @@ -75,6 +76,8 @@ app.use('/groups', groupRouter)

app.use('/rooms', roomRouter)

app.use('/favorites', favoriteRouter)

app.use('/tickets', ticketRouter)

/**
Expand Down
27 changes: 27 additions & 0 deletions src/components/favorites/favorite.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Router } from 'express'
import { check } from 'express-validator'

import { isAuthenticated } from '../../config/passport'
import { handleValidationError } from '../../util/validators'
import { addFavorite, removeFavorite } from './favorite.service'

const router = Router()

router.post('/',
isAuthenticated,
check('room')
.notEmpty()
.isInt({ gt: 2, lt: 19 })
.withMessage('A szint csak üres vagy 3 és 18 közötti szám lehet'),
handleValidationError(400),
addFavorite,
(req, res) => res.sendStatus(201)
)

router.delete('/:id',
isAuthenticated,
removeFavorite,
(req, res) => res.sendStatus(201)
)

export default router
45 changes: 45 additions & 0 deletions src/components/favorites/favorite.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Request, Response, NextFunction } from 'express'
import { asyncWrapper } from '../../util/asyncWrapper'
import { User } from '../users/user'

export const addFavorite = asyncWrapper(
async (req: Request, res: Response, next: NextFunction) => {
const favorites = await User.relatedQuery('favorites').for(
(req.user as User).id
)
if (
favorites &&
!favorites.some((element) => element.room == parseInt(req.params.id))
) {
await User.relatedQuery('favorites')
.for((req.user as User).id)
.insert({
room: parseInt(req.body.room),
})
next()
} else {
res.sendStatus(404)
}
}
)

export const removeFavorite = asyncWrapper(
async (req: Request, res: Response, next: NextFunction) => {
const favorites = await User.relatedQuery('favorites').for(
(req.user as User).id
)
if (
req.params.id &&
favorites &&
favorites.some((element) => element.room == parseInt(req.params.id))
) {
await User.relatedQuery('favorites')
.for((req.user as User).id)
.delete()
.where({ room: parseInt(req.params.id) })
next()
} else {
res.sendStatus(404)
}
}
)
38 changes: 38 additions & 0 deletions src/components/favorites/favorite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Model } from 'objection'

import { User } from '../users/user'

export class Favorite extends Model {
id!: number
room: number
user: User
static get tableName() {
return 'favorites'
}

static get relationMappings() {
return {
user: {
relation: Model.BelongsToOneRelation,
modelClass: User,

join: {
from: 'favorites.userId',
to: 'users.id'
}
}
}
}

static get jsonSchema() {
return {
type: 'object',
required: ['room'],

properties: {
id: { type: 'integer' },
room: { type: 'integer' },
}
}
}
}
20 changes: 19 additions & 1 deletion src/components/rooms/room.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,28 @@ import { Request, Response, Router } from 'express'
import { getBusyRooms, getEventsForRoom } from './room.service'
import { ROOMS } from '../../util/constants'
import { asyncWrapper } from '../../util/asyncWrapper'
import { User } from '../users/user'

export const index = asyncWrapper(async (req: Request, res: Response) => {
const busyRooms = await getBusyRooms()
res.render('room/index', { busyRooms, ROOMS })
let rooms = ROOMS.map(floor => {
return {
floor,
busy: busyRooms.find(el => el.id == floor)
}
})
if (req.user) {
const user = (req.user as User)
const favorites = await User.relatedQuery('favorites').for(user.id)
if (favorites && favorites.length > 0)
rooms = rooms.map(room => {
return {
...room,
favorite: favorites.some(el => el.room == room.floor)
}
})
}
res.render('room/index', { rooms })
})

const show = asyncWrapper(async (req: Request, res: Response) => {
Expand Down
13 changes: 11 additions & 2 deletions src/components/users/user.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Model } from 'objection'
import { Favorite } from '../favorites/favorite'

import { Group } from '../groups/group'

Expand All @@ -8,8 +9,8 @@ export class User extends Model {
email: string
authSchId: string
admin: boolean
floor: number
groups: Group[]
favorites: Favorite[]
static get tableName() {
return 'users'
}
Expand All @@ -28,6 +29,15 @@ export class User extends Model {
},
to: 'groups.id'
}
},
favorites: {
relation: Model.HasManyRelation,
modelClass: Favorite,

join: {
from: 'users.id',
to: 'favorites.userId'
}
}
}
}
Expand All @@ -41,7 +51,6 @@ export class User extends Model {
id: { type: 'integer' },
name: { type: 'string', minLength: 1, maxLength: 255 },
authSchId: { type: 'string' },
floor: { type: ['integer', 'null'] }
}
}
}
Expand Down
Loading