kungtinglin 6 rokov pred
rodič
commit
a7b4bb62b0

+ 50 - 0
migrations/20191202014433-create_equipments_table.js

@@ -0,0 +1,50 @@
+'use strict'
+
+module.exports = {
+  /**
+   * @param {Types} Sequelize
+   */
+  up: (queryInterface, Sequelize) => {
+    return queryInterface.createTable('equipments', {
+      id: {
+        primaryKey: true,
+        autoIncrement: true,
+        type: Sequelize.BIGINT.UNSIGNED
+      },
+
+      name: {
+        allowNull: false,
+        type: Sequelize.STRING(30)
+      },
+
+      current_user_id: {
+        type: Sequelize.BIGINT.UNSIGNED,
+        references: {
+          model: {
+            tableName: 'users'
+          },
+          key: 'id'
+        }
+      }
+    })
+
+    /*
+      Add altering commands here.
+      Return a promise to correctly handle asynchronicity.
+
+      Example:
+      return queryInterface.createTable('users', { id: Sequelize.INTEGER });
+    */
+  },
+
+  down: (queryInterface, Sequelize) => {
+    return queryInterface.dropTable('equipments')
+    /*
+      Add reverting commands here.
+      Return a promise to correctly handle asynchronicity.
+
+      Example:
+      return queryInterface.dropTable('users');
+    */
+  }
+}

+ 35 - 0
migrations/20191202054738-create_sites_table.js

@@ -0,0 +1,35 @@
+'use strict'
+
+module.exports = {
+  up: (queryInterface, Sequelize) => {
+    return queryInterface.createTable('sites', {
+      id: {
+        primaryKey: true,
+        autoIncrement: true,
+        type: Sequelize.BIGINT.UNSIGNED
+      },
+
+      name: {
+        allowNull: false,
+        type: Sequelize.STRING(20)
+      }
+    })
+    /*
+      Add altering commands here.
+      Return a promise to correctly handle asynchronicity.
+
+      Example:
+      return queryInterface.createTable('users', { id: Sequelize.INTEGER });
+    */
+  },
+
+  down: (queryInterface, Sequelize) => {
+    /*
+      Add reverting commands here.
+      Return a promise to correctly handle asynchronicity.
+
+      Example:
+      return queryInterface.dropTable('users');
+    */
+  }
+}

+ 35 - 0
migrations/20191202055630-add_site_id_to_equipments_table.js

@@ -0,0 +1,35 @@
+'use strict'
+
+module.exports = {
+  up: async (queryInterface, Sequelize) => {
+    await queryInterface.addColumn('equipments', 'site_id', {
+      type: Sequelize.BIGINT.UNSIGNED,
+      allowNull: false
+    })
+
+    await queryInterface.addConstraint('equipments', ['site_id'], {
+      type: 'foreign key',
+      references: {
+        table: 'sites',
+        field: 'id'
+      }
+    })
+    /*
+      Add altering commands here.
+      Return a promise to correctly handle asynchronicity.
+
+      Example:
+      return queryInterface.createTable('users', { id: Sequelize.INTEGER });
+    */
+  },
+
+  down: (queryInterface, Sequelize) => {
+    /*
+      Add reverting commands here.
+      Return a promise to correctly handle asynchronicity.
+
+      Example:
+      return queryInterface.dropTable('users');
+    */
+  }
+}

+ 1 - 1
seeders/20191127135703-EquipmentDataSeeder.js

@@ -7,7 +7,7 @@ const alarms = ['Normal', 'Alarm', 'Low Battery']
 function getEqumentData(ap_id) {
   return {
     ap_id,
-    aid_id: `輔具編號 ${faker.random.number(5)}`,
+    aid_id: faker.random.number({ min: 1, max: 10 }),
     beacon_id: faker.hacker.noun() + faker.random.number({ min: 100, max: 999 }),
     status: faker.random.number(3).toString(),
     battery: faker.random.number(100),

+ 44 - 0
seeders/20191202025223-EquipmentSeeder.js

@@ -0,0 +1,44 @@
+'use strict'
+const faker = require('faker')
+
+module.exports = {
+  up: async (queryInterface, Sequelize) => {
+    await queryInterface.bulkInsert(
+      'sites',
+      Array.from(Array(4).keys()).map(index => ({
+        name: `工地 ${index}`
+      }))
+    )
+
+    const sites = (await queryInterface.sequelize.query('SELECT id FROM sites'))[0]
+
+    await queryInterface.bulkInsert(
+      'equipments',
+      Array.from(Array(10).keys()).map(index => ({
+        name: `輔具編號 ${index}`,
+        site_id: sites[faker.random.number({ min: 0, max: sites.length - 1 })].id
+      }))
+    )
+    /*
+      Add altering commands here.
+      Return a promise to correctly handle asynchronicity.
+
+      Example:
+      return queryInterface.bulkInsert('People', [{
+        name: 'John Doe',
+        isBetaMember: false
+      }], {});
+    */
+  },
+
+  down: (queryInterface, Sequelize) => {
+    return queryInterface.bulkDelete('equipments', null, {})
+    /*
+      Add reverting commands here.
+      Return a promise to correctly handle asynchronicity.
+
+      Example:
+      return queryInterface.bulkDelete('People', null, {});
+    */
+  }
+}

+ 13 - 0
src/controllers/AuthController.ts

@@ -2,6 +2,7 @@ import { Request, Response } from 'express'
 import { User } from '../database/models/User'
 import UserService from '../services/UserService'
 import bcrypt from 'bcrypt'
+import { networkError } from './Error'
 
 class AuthController {
   async login(req: Request, res: Response) {
@@ -13,6 +14,18 @@ class AuthController {
 
     return res.json({ token: UserService.generateLoginToken(user.id) })
   }
+
+  async getUsers(_: any, res: Response) {
+    try {
+      const users = await User.findAll({
+        attributes: ['id', 'name']
+      })
+
+      res.json(users)
+    } catch (error) {
+      networkError(res, JSON.stringify(error))
+    }
+  }
 }
 
 export default AuthController

+ 37 - 7
src/controllers/EquipmentController.ts

@@ -1,20 +1,50 @@
 import { Request, Response } from 'express'
-import { EquipmentData } from '../database/models/EquipmentData'
+import { User } from '../database/models/User'
+import { Equipment } from '../database/models/Equipment'
 import { sequelize } from '../database'
+import { networkError } from './Error'
 
 class EquipmentController {
   async getEquipments(req: Request, res: Response) {
     try {
       const result = await sequelize.query(
-        'SELECT *  FROM equipment_data WHERE id IN (SELECT max(id) FROM equipment_data GROUP BY aid_id)'
+        `SELECT * FROM equipment_data
+         JOIN equipments ON aid_id = equipments.id
+         WHERE equipment_data.id IN
+           (SELECT max(id) FROM equipment_data GROUP BY aid_id)
+         `
       )
 
       res.json(result[0])
-    } catch (err) {
-      res.status(500).json({
-        msg: 'Internal network error',
-        reason: JSON.stringify(err)
-      })
+    } catch (error) {
+      networkError(res, JSON.stringify(error))
+    }
+  }
+
+  async assignUserToEquipment(req: Request, res: Response) {
+    try {
+      const { user_id: userId, equipment_id: equipmentId } = req.body
+      const user = await User.findByPk(userId)
+      const equipment = await Equipment.findByPk(equipmentId)
+
+      if (!user) {
+        res.status(400).json({
+          message: 'User not found'
+        })
+        return
+      }
+
+      if (!equipment) {
+        res.status(400).json({
+          message: 'Equipment not found'
+        })
+        return
+      }
+
+      await equipment.update({ current_user_id: user.id })
+      res.status(200).json({ message: 'ok' })
+    } catch (error) {
+      networkError(res, JSON.stringify(error))
     }
   }
 }

+ 8 - 0
src/controllers/Error.ts

@@ -0,0 +1,8 @@
+import { Response } from 'express'
+
+export function networkError(res: Response, error: string) {
+  res.status(500).json({
+    msg: 'Internal network error',
+    reason: JSON.stringify(error)
+  })
+}

+ 13 - 0
src/database/models/Equipment.ts

@@ -0,0 +1,13 @@
+import { Model, Table, Column, Unique, Default, CreatedAt, UpdatedAt } from 'sequelize-typescript'
+
+@Table({ tableName: 'equipments', timestamps: false })
+export class Equipment extends Model<Equipment> {
+  @Column
+  name: string
+
+  @Column
+  current_user_id: Number
+
+  @Column
+  site_id: Number
+}

+ 7 - 0
src/database/models/Site.ts

@@ -0,0 +1,7 @@
+import { Model, Table, Column, Unique, Default, CreatedAt, UpdatedAt } from 'sequelize-typescript'
+
+@Table({ tableName: 'sites', timestamps: false })
+export class Site extends Model<Site> {
+  @Column
+  name: string
+}

+ 5 - 0
src/requests/AssignEquipmentRequest.ts

@@ -0,0 +1,5 @@
+import { check } from 'express-validator'
+
+const AssignEquipmentRequest = [check('user_id').exists(), check('equipment_id').exists()]
+
+export default AssignEquipmentRequest

+ 9 - 1
src/routes.ts

@@ -1,4 +1,5 @@
 import LoginRequest from './requests/LoginRequest'
+import AssignEquipmentRequest from './requests/AssignEquipmentRequest'
 import { ValidationChain } from 'express-validator'
 
 interface route {
@@ -20,5 +21,12 @@ export const routes: Array<route> = [
     url: '/equipments',
     method: 'get',
     action: 'EquipmentController@getEquipments'
-  }
+  },
+  {
+    url: '/assignEquipment',
+    method: 'post',
+    action: 'EquipmentController@assignUserToEquipment',
+    validator: AssignEquipmentRequest
+  },
+  { url: '/users', method: 'get', action: 'AuthController@getUsers' }
 ]