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

Jugurtha/api_certificat #462

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,6 @@ typings/
/toolbox.dev/data

# Migration data backup
db-migrations/migrations/data-backup
db-migrations/migrations/data-backup
# Ignorer tout le contenu du dossier db-migrations/data/
db-migrations/data
84 changes: 84 additions & 0 deletions db-migrations/migrations/20240808162138-init-certificate-table.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
'use strict'

require('dotenv').config()

const {POSTGRES_BAN_USER} = process.env

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface, Sequelize) {
try {
// Create ban schema if not exists
await queryInterface.sequelize.query('CREATE SCHEMA IF NOT EXISTS ban;')

// Grant permissions to ban user on schema ban
await queryInterface.sequelize.query(
`GRANT USAGE ON SCHEMA ban TO "${POSTGRES_BAN_USER}";`
)

// Create Certificate Table if not exists
await queryInterface.createTable(
'certificate',
{
id: {
type: Sequelize.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
},
// eslint-disable-next-line camelcase
address_id: {
type: Sequelize.UUID,
allowNull: false,
references: {
model: {
tableName: 'address',
schema: 'ban',
},
key: 'id',
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
},
// eslint-disable-next-line camelcase
full_address: {
type: Sequelize.JSONB,
allowNull: false,
},
// eslint-disable-next-line camelcase
cadastre_ids: {
type: Sequelize.ARRAY(Sequelize.STRING),
allowNull: true,
},
createdAt: {
type: Sequelize.DATE,
defaultValue: Sequelize.NOW,
},
},
{
schema: 'ban',
timestamps: false,
ifNotExists: true,
}
)

// Grant permissions to ban user on the certificate table
await queryInterface.sequelize.query(
`GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE ban.certificate TO "${POSTGRES_BAN_USER}";`
)
} catch (error) {
console.error(error)
}
},

async down(queryInterface) {
try {
// Drop the Certificate table
await queryInterface.sequelize.query(
'DROP TABLE IF EXISTS ban.certificate CASCADE;'
)
} catch (error) {
console.error(error)
}
},
}
56 changes: 56 additions & 0 deletions lib/api/certificate/models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import {Certificate, sequelize} from '../../util/sequelize.js'

const getDataForCertificateQuery = `
SELECT
a.id as "addressID",
a.number as "addressNumber",
a.suffix as "addressSuffix",
ct.labels[1]->>'value' as "commonToponymDefaultLabel",
d.labels[1]->>'value' as "districtDefaultLabel",
d.meta->'insee'->>'cog' as "districtCog",
d.config as "districtConfig",
a.meta->'cadastre'->'ids' as "cadastreIDs",
a.certified,
a."isActive"
FROM
"ban"."address" AS a
JOIN
"ban"."district" AS d ON a."districtID" = d.id
LEFT JOIN
"ban"."common_toponym" AS ct ON ct.id = a."mainCommonToponymID"
WHERE
a.id = :addressId
and a.certified=true
and a."isActive"=true
and jsonb_array_length(a.meta->'cadastre'->'ids') > 0

`

export const getCertificate = certificateID => Certificate.findByPk(certificateID, {raw: true})

export const getCertificates = certificateIDs => Certificate.findAll({
where: {id: certificateIDs},
raw: true
})

export const getCertificatesByAddress = addressID => Certificate.findAll({
where: {address_id: addressID}, // eslint-disable-line camelcase
raw: true
})

export const setCertificate = async certificate => Certificate.create(certificate)

export const getDataForCertificate = async addressId => {
try {
const [data] = await sequelize.query(getDataForCertificateQuery, {
replacements: {addressId},
raw: true,
})

console.log(`Data for certificate: ${JSON.stringify(data)}`)
return data[0]
} catch (error) {
console.error(`Error executing query: ${error.message}`)
throw error
}
}
58 changes: 58 additions & 0 deletions lib/api/certificate/routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import 'dotenv/config.js' // eslint-disable-line import/no-unassigned-import
import express from 'express'
import auth from '../../middleware/auth.js'
import {
getCertificate,
setCertificate,
getDataForCertificate
} from './models.js'
import {formatDataForCertificate} from './utils.js'

const app = new express.Router()
app.use(express.json())

app.get('/:id', async (req, res) => {
const {id} = req.params
try {
const certificate = await getCertificate(id)
if (certificate) {
res.status(200).json(certificate)
} else {
res.status(404).json({message: 'Certificate not found'})
}
} catch (error) {
console.error(`Error retrieving certificate: ${error.message}`)
res.status(500).json({message: 'Internal server error'})
}
})

app.post('/', auth, async (req, res) => {
try {
const {addressID} = req.body

if (!addressID) {
return res.status(400).json({message: 'addressID is required'})
}

const data = await getDataForCertificate(addressID)

if (!data) {
return res.status(400).json({message: 'Address is not certified, not active, or has no parcels.'})
}

const {districtConfig} = data
if (!districtConfig.certificate) {
return res.status(400).json({message: 'District has not activated the certificate config.'})
}

const certificate = await formatDataForCertificate(data)
const newCertificate = await setCertificate(certificate)

res.status(201).json(newCertificate)
} catch (error) {
console.error(`Error creating certificate: ${error.message}`)
res.status(500).json({message: 'Internal server error'})
}
})

export default app
15 changes: 15 additions & 0 deletions lib/api/certificate/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const formatDataForCertificate = data => {
const fullAddress = {
number: data.addressNumber,
commonToponymDefaultLabel: data.commonToponymDefaultLabel,
suffix: data.addressSuffix,
districtDefaultLabel: data.districtDefaultLabel,
cog: data.districtCog,
}

return {
address_id: data.addressID, // eslint-disable-line camelcase
full_address: fullAddress, // eslint-disable-line camelcase
cadastre_ids: data.cadastreIDs, // eslint-disable-line camelcase
}
}
6 changes: 4 additions & 2 deletions lib/api/district/schema.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import {object, string, array, date, bool} from 'yup'
import {object, string, array, date} from 'yup'
import {banID, labelSchema, balSchema} from '../schema.js'

const certificateSchema = object({}).noUnknown()

const configSchema = object({
useBanId: bool()
certificate: certificateSchema,
}).noUnknown()

const inseeSchema = object({
Expand Down
2 changes: 2 additions & 0 deletions lib/api/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import commonToponymRoutes from './common-toponym/routes.js'
import districtRoutes from './district/routes.js'
import statusRoutes from './job-status/routes.js'
import banIdRoutes from './ban-id/routes.js'
import certificatRoutes from './certificate/routes.js'

const app = new express.Router()

Expand All @@ -14,5 +15,6 @@ app.use('/common-toponym', commonToponymRoutes)
app.use('/district', districtRoutes)
app.use('/job-status', statusRoutes)
app.use('/ban-id', banIdRoutes)
app.use('/certificate', certificatRoutes)

export default app
34 changes: 34 additions & 0 deletions lib/util/sequelize.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,40 @@ export const JobStatus = sequelize.define('JobStatus', {
tableName: 'job_status'
})

export const Certificate = sequelize.define('Certificate', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
address_id: { // eslint-disable-line camelcase
type: DataTypes.UUID,
allowNull: false,
references: {
model: 'address',
key: 'id',
},
},
// eslint-disable-next-line camelcase
full_address: {
type: DataTypes.JSONB,
allowNull: false,
},
// eslint-disable-next-line camelcase
cadastre_ids: {
type: DataTypes.ARRAY(DataTypes.STRING),
allowNull: true,
},
createdAt: {
type: DataTypes.DATE,
defaultValue: Sequelize.NOW,
}
}, {
schema: 'ban',
tableName: 'certificate',
timestamps: false,
})

export const init = async () => {
try {
await sequelize.authenticate()
Expand Down
Loading