diff --git a/Makefile b/Makefile index 3ea412a..138f0a3 100644 --- a/Makefile +++ b/Makefile @@ -14,4 +14,8 @@ lint: build: docker-compose build +.PHONY: migrate +migrate: + docker exec -it soroka-backend npm run migrate + .DEFAULT_GOAL := build diff --git a/src/controllers/dates/DateCatalog.ts b/src/controllers/dates/DateCatalog.ts new file mode 100644 index 0000000..5e03e18 --- /dev/null +++ b/src/controllers/dates/DateCatalog.ts @@ -0,0 +1,21 @@ +import { Request, Response } from "express" +import DateCatalogService from '../../services/dates/DateCatalog' + +class DateCatalogController { + private dateCatalogService: DateCatalogService + + constructor() { + this.dateCatalogService = new DateCatalogService() + } + + list = async (request: Request, response: Response) => { + const dateStart = Number(request.query.dateStart) + const dateEnd = Number(request.query.dateEnd) + + const properties = await this.dateCatalogService.list(dateStart, dateEnd) + + return response.send(properties) + } +} + +export default DateCatalogController diff --git a/src/core/swagger.json b/src/core/swagger.json index be574c1..1c3fd86 100644 --- a/src/core/swagger.json +++ b/src/core/swagger.json @@ -486,6 +486,38 @@ } } } + }, + "/dates": { + "get": { + "description": "Свойства по карточке", + "tags": ["dates"], + "parameters": [ + { + "name": "dateStart", + "in": "query", + "required": true, + "type": "number", + "example": 2459727 + }, + { + "name": "dateEnd", + "in": "query", + "required": true, + "type": "number", + "example": 2459827 + } + ], + "responses": { + "200": { + "name": "obj", + "in": "body", + "description": "Свойства, соответствующие фильтру", + "schema": { + "$ref": "#/definitions/FilledPropertiesResponse" + } + } + } + } } }, "definitions": { diff --git a/src/migrations/20220531093736-calendar.js b/src/migrations/20220531093736-calendar.js new file mode 100644 index 0000000..3271948 --- /dev/null +++ b/src/migrations/20220531093736-calendar.js @@ -0,0 +1,28 @@ +'use strict'; +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('Calendars', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + allowNull: false, + type: Sequelize.STRING + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('Calendars'); + } +}; diff --git a/src/migrations/20220531102806-date-catalog.js b/src/migrations/20220531102806-date-catalog.js new file mode 100644 index 0000000..763efbc --- /dev/null +++ b/src/migrations/20220531102806-date-catalog.js @@ -0,0 +1,42 @@ +'use strict'; +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('DateCatalogs', { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + filledPropertyId: { + type: Sequelize.DataTypes.INTEGER, + references: { + model: { + tableName: 'FilledProperties', + }, + key: 'id' + }, + allowNull: false + }, + dateStart: { + allowNull: false, + type: Sequelize.FLOAT + }, + dateEnd: { + allowNull: false, + type: Sequelize.FLOAT + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('DateCatalogs'); + } +}; diff --git a/src/models/cards/FilledProperty.ts b/src/models/cards/FilledProperty.ts index db21078..ae860b2 100644 --- a/src/models/cards/FilledProperty.ts +++ b/src/models/cards/FilledProperty.ts @@ -1,5 +1,16 @@ -import { Table, Column, Model, AllowNull, ForeignKey, BelongsToMany, DataType as DT } from 'sequelize-typescript' +import { + Table, + Column, + Model, + AllowNull, + ForeignKey, + BelongsToMany, + DataType as DT, + BeforeUpdate +} from 'sequelize-typescript' import Card, { FilledPropertyCard } from './Card' +import DataType from './DataType' +import DateCatalog from '../dates/DateCatalog' import Property from './Property' @Table @@ -18,6 +29,30 @@ class FilledProperty extends Model { @BelongsToMany(() => Card, () => FilledPropertyCard) cardsList: Card[] + + @BeforeUpdate + static async onJulianDateChanged(instance: FilledProperty) { + // FIXME: добавить BelongsTo во всех связанных моделях + // чтобы делать запросы через related getter + const property = await Property.findByPk(instance.propertyId) + const dataType = await DataType.findByPk(property?.dataTypeId) + + const isJulianDate = dataType?.name === 'JULIAN_DATE' + + if (isJulianDate) { + const data: any = JSON.parse(instance.data) + + // FIXME: в будущем будут периоды дат и тд + // сейчас просто заглушка для определения + // даты начала и окончания + const dateStart = data[0].jd + const dateEnd = data[0].jd + + const filledPropertyId = instance.id + + await DateCatalog.create({ dateStart, dateEnd, filledPropertyId }) + } + } } export default FilledProperty diff --git a/src/models/dates/Calendar.ts b/src/models/dates/Calendar.ts new file mode 100644 index 0000000..007cb66 --- /dev/null +++ b/src/models/dates/Calendar.ts @@ -0,0 +1,10 @@ +import { Table, Column, Model, AllowNull } from 'sequelize-typescript' + +@Table +class Calendar extends Model { + @AllowNull(false) + @Column + name: string +} + +export default Calendar diff --git a/src/models/dates/DateCatalog.ts b/src/models/dates/DateCatalog.ts new file mode 100644 index 0000000..734943d --- /dev/null +++ b/src/models/dates/DateCatalog.ts @@ -0,0 +1,25 @@ +import { Table, Column, Model, AllowNull, ForeignKey, Scopes, DataType as DT } from 'sequelize-typescript' +import FilledProperty from '../cards/FilledProperty' + +@Scopes(() => ({ + properties: { + attributes: ['filledPropertyId'] + } +})) +@Table +class DateCatalog extends Model { + @AllowNull(false) + @Column(DT.FLOAT) + dateStart: string + + @AllowNull(false) + @Column(DT.FLOAT) + dateEnd: string + + @AllowNull(false) + @ForeignKey(() => FilledProperty) + @Column + filledPropertyId: number +} + +export default DateCatalog diff --git a/src/models/users/User.ts b/src/models/users/User.ts index a27312b..4db7f30 100644 --- a/src/models/users/User.ts +++ b/src/models/users/User.ts @@ -8,13 +8,23 @@ import { AfterCreate, BeforeCreate, BeforeUpdate, - ForeignKey + ForeignKey, + DefaultScope, + Scopes } from 'sequelize-typescript' import hashPassword from '../../utils/hashPassword' import AuthorizationLink from '../auth/AuthorizationLink' import Organization from '../organizations/Organization' import UserRole from './UserRole' +@DefaultScope(() => ({ + attributes: ['id', 'name', 'email', 'hasAcceptTermsOfUse', 'userRole', 'organization'] +})) +@Scopes(() => ({ + auth: { + attributes: ['id', 'email', 'password'] + } +})) @Table class User extends Model { @AllowNull(false) diff --git a/src/providers/db.ts b/src/providers/db.ts index 104342d..c88ebe7 100644 --- a/src/providers/db.ts +++ b/src/providers/db.ts @@ -6,6 +6,8 @@ import CardTemplate from '../models/cards/CardTemplate' import DataType from '../models/cards/DataType' import FilledProperty from '../models/cards/FilledProperty' import Property from '../models/cards/Property' +import Calendar from '../models/dates/Calendar' +import DateCatalog from '../models/dates/DateCatalog' import Organization from '../models/organizations/Organization' import User from '../models/users/User' import UserRole from '../models/users/UserRole' @@ -27,7 +29,9 @@ const models = [ DataType, Property, FilledProperty, Card, CardTemplate, - FilledPropertyCard + FilledPropertyCard, + DateCatalog, + Calendar ] sequelize.addModels(models) diff --git a/src/routes/admin/admin.ts b/src/routes/admin/admin.ts index 776ace6..00c210c 100644 --- a/src/routes/admin/admin.ts +++ b/src/routes/admin/admin.ts @@ -16,13 +16,16 @@ const FilledProperty = sequelize.model('FilledProperty') const CardTemplate = sequelize.model('CardTemplate') const Card = sequelize.model('Card') const FilledPropertyCard = sequelize.model('FilledPropertyCard') +const DateCatalog = sequelize.model('DateCatalog') +const Calendar = sequelize.model('Calendar') const adminJs = new AdminJS({ resources: [ User, UserRole, Organization, AuthorizationLink, RefreshToken, DataType, Property, FilledProperty, - CardTemplate, Card, FilledPropertyCard + CardTemplate, Card, FilledPropertyCard, + DateCatalog, Calendar ], branding: { companyName: 'AdminJS', diff --git a/src/routes/v1/dates/DateCatalog.ts b/src/routes/v1/dates/DateCatalog.ts new file mode 100644 index 0000000..cbd5666 --- /dev/null +++ b/src/routes/v1/dates/DateCatalog.ts @@ -0,0 +1,11 @@ +import DateCatalogController from '../../../controllers/dates/DateCatalog' +import express from "express" + +const router: express.Router = express.Router() + +const controller: DateCatalogController = new DateCatalogController() + +router.route('/') + .get(controller.list) + +export default router diff --git a/src/routes/v1/index.ts b/src/routes/v1/index.ts index 0cb9b5a..8ab7cc6 100644 --- a/src/routes/v1/index.ts +++ b/src/routes/v1/index.ts @@ -7,6 +7,7 @@ import filledPropertiesRoutes from "./cards/FilledProperty" import cardRoutes from "./cards/Card" import cardTemplateRoutes from "./cards/CardTemplate" import organizationRoutes from "./organizations/Organization" +import dateRoutes from "./dates/DateCatalog" const router: express.Router = express.Router() @@ -18,5 +19,6 @@ router.use('/cards/properties', propertyRoutes) router.use('/cards/filled-properties', filledPropertiesRoutes) router.use('/authorization-link', authorizationLinkRoutes) router.use('/organizations', organizationRoutes) +router.use('/dates', dateRoutes) export default router diff --git a/src/services/dates/DateCatalog.ts b/src/services/dates/DateCatalog.ts new file mode 100644 index 0000000..13967b7 --- /dev/null +++ b/src/services/dates/DateCatalog.ts @@ -0,0 +1,26 @@ +import FilledProperty from "../../models/cards/FilledProperty" +import DateCatalog from "../../models/dates/DateCatalog" +import { Op } from 'sequelize' + +class DateCatalogService { + async list(dateStart: number, dateEnd: number) { + const filteredProperties = await DateCatalog.scope('properties').findAll({ + where: { + dateStart: { [Op.gte]: dateStart }, + dateEnd: { [Op.lte]: dateEnd } + } + }) + + const filteredPropertiesIds = filteredProperties.map((prop) => prop.filledPropertyId) + + const propertiesList = await FilledProperty.findAll({ + where: { + id: { [Op.in]: filteredPropertiesIds } + } + }) + + return propertiesList + } +} + +export default DateCatalogService diff --git a/src/services/users/User.ts b/src/services/users/User.ts index 52f1878..4aab334 100644 --- a/src/services/users/User.ts +++ b/src/services/users/User.ts @@ -24,7 +24,7 @@ class UserService { } async checkPassword(email: string, password: string) : Promise { - const user = await User.findOne({ where: { email } }) + const user = await User.scope('auth').findOne({ where: { email } }) if (user) return { user: user.toJSON(), checkPassword: checkPassword(user, password) }