11import { Router } from 'express'
22
3- import sql = require( '../lib/sql' )
4- const { grants, roles } = sql
3+ import SQL from 'sql-template-strings'
4+ import sqlTemplates = require( '../lib/sql' )
5+ const { grants, roles } = sqlTemplates
56import { coalesceRowsToArray } from '../lib/helpers'
67import { RunQuery } from '../lib/connectionPool'
78import { DEFAULT_ROLES , DEFAULT_SYSTEM_SCHEMAS } from '../lib/constants'
@@ -37,13 +38,53 @@ router.get('/', async (req, res) => {
3738
3839router . post ( '/' , async ( req , res ) => {
3940 try {
40- const sql = createRoleSqlize ( req . body )
41- const { data } = await RunQuery ( req . headers . pg , sql )
42- return res . status ( 200 ) . json ( data )
41+ const query = createRoleSqlize ( req . body )
42+ await RunQuery ( req . headers . pg , query )
43+
44+ const getRoleQuery = singleRoleByNameSqlize ( roles , req . body . name )
45+ const role = ( await RunQuery ( req . headers . pg , getRoleQuery ) ) . data [ 0 ]
46+
47+ return res . status ( 200 ) . json ( role )
48+ } catch ( error ) {
49+ console . log ( 'throwing error' , error )
50+ res . status ( 500 ) . json ( { error : 'Database error' , status : 500 } )
51+ }
52+ } )
53+
54+ router . patch ( '/:id' , async ( req , res ) => {
55+ try {
56+ const id = req . params . id
57+ const getRoleQuery = singleRoleSqlize ( roles , id )
58+ const role = ( await RunQuery ( req . headers . pg , getRoleQuery ) ) . data [ 0 ]
59+ const { name : oldName } = role
60+
61+ const alterRoleArgs = req . body
62+ alterRoleArgs . oldName = oldName
63+ const query = alterRoleSqlize ( alterRoleArgs )
64+ await RunQuery ( req . headers . pg , query )
65+
66+ const updated = ( await RunQuery ( req . headers . pg , getRoleQuery ) ) . data [ 0 ]
67+ return res . status ( 200 ) . json ( updated )
68+ } catch ( error ) {
69+ console . log ( 'throwing error' , error )
70+ res . status ( 500 ) . json ( { error : 'Database error' , status : 500 } )
71+ }
72+ } )
73+
74+ router . delete ( '/:id' , async ( req , res ) => {
75+ try {
76+ const id = req . params . id
77+ const getRoleQuery = singleRoleSqlize ( roles , id )
78+ const role = ( await RunQuery ( req . headers . pg , getRoleQuery ) ) . data [ 0 ]
79+ const { name } = role
80+
81+ const query = dropRoleSqlize ( name )
82+ await RunQuery ( req . headers . pg , query )
83+
84+ return res . status ( 200 ) . json ( role )
4385 } catch ( error ) {
44- // For this one, we always want to give back the error to the customer
45- console . log ( 'Soft error!' , error )
46- res . status ( 200 ) . json ( [ { error : error . toString ( ) } ] )
86+ console . log ( 'throwing error' , error )
87+ res . status ( 500 ) . json ( { error : 'Database error' , status : 500 } )
4788 }
4889} )
4990
@@ -103,7 +144,7 @@ const createRoleSqlize = ({
103144 const adminsSql = admins === undefined ? '' : `ADMIN ${ admins . join ( ',' ) } `
104145
105146 return `
106- CREATE ROLE ${ name }
147+ CREATE ROLE " ${ name } "
107148WITH
108149 ${ isSuperuserSql }
109150 ${ canCreateDbSql }
@@ -119,6 +160,92 @@ WITH
119160 ${ membersSql }
120161 ${ adminsSql } `
121162}
163+ const singleRoleSqlize = ( roles : string , id : string ) => {
164+ return SQL `` . append ( roles ) . append ( SQL ` WHERE oid = ${ id } ` )
165+ }
166+ const singleRoleByNameSqlize = ( roles : string , name : string ) => {
167+ return SQL `` . append ( roles ) . append ( SQL ` WHERE rolname = ${ name } ` )
168+ }
169+ const alterRoleSqlize = ( {
170+ oldName,
171+ name,
172+ isSuperuser,
173+ canCreateDb,
174+ canCreateRole,
175+ inheritRole,
176+ canLogin,
177+ isReplicationRole,
178+ canBypassRls,
179+ connectionLimit,
180+ password,
181+ validUntil,
182+ } : {
183+ oldName : string
184+ name ?: string
185+ isSuperuser ?: boolean
186+ canCreateDb ?: boolean
187+ canCreateRole ?: boolean
188+ inheritRole ?: boolean
189+ canLogin ?: boolean
190+ isReplicationRole ?: boolean
191+ canBypassRls ?: boolean
192+ connectionLimit ?: number
193+ password ?: string
194+ validUntil ?: string
195+ } ) => {
196+ const nameSql = name === undefined ? '' : `ALTER ROLE "${ oldName } " RENAME TO "${ name } ";`
197+ let isSuperuserSql = ''
198+ if ( isSuperuser !== undefined ) {
199+ isSuperuserSql = isSuperuser ? 'SUPERUSER' : 'NOSUPERUSER'
200+ }
201+ let canCreateDbSql = ''
202+ if ( canCreateDb !== undefined ) {
203+ canCreateDbSql = canCreateDb ? 'CREATEDB' : 'NOCREATEDB'
204+ }
205+ let canCreateRoleSql = ''
206+ if ( canCreateRole !== undefined ) {
207+ canCreateRoleSql = canCreateRole ? 'CREATEROLE' : 'NOCREATEROLE'
208+ }
209+ let inheritRoleSql = ''
210+ if ( inheritRole !== undefined ) {
211+ inheritRoleSql = inheritRole ? 'INHERIT' : 'NOINHERIT'
212+ }
213+ let canLoginSql = ''
214+ if ( canLogin !== undefined ) {
215+ canLoginSql = canLogin ? 'LOGIN' : 'NOLOGIN'
216+ }
217+ let isReplicationRoleSql = ''
218+ if ( isReplicationRole !== undefined ) {
219+ isReplicationRoleSql = isReplicationRole ? 'REPLICATION' : 'NOREPLICATION'
220+ }
221+ let canBypassRlsSql = ''
222+ if ( canBypassRls !== undefined ) {
223+ canBypassRlsSql = canBypassRls ? 'BYPASSRLS' : 'NOBYPASSRLS'
224+ }
225+ const connectionLimitSql =
226+ connectionLimit === undefined ? '' : `CONNECTION LIMIT ${ connectionLimit } `
227+ let passwordSql = password === undefined ? '' : `PASSWORD '${ password } '`
228+ let validUntilSql = validUntil === undefined ? '' : `VALID UNTIL '${ validUntil } '`
229+
230+ return `
231+ BEGIN;
232+ ALTER ROLE "${ oldName } "
233+ ${ isSuperuserSql }
234+ ${ canCreateDbSql }
235+ ${ canCreateRoleSql }
236+ ${ inheritRoleSql }
237+ ${ canLoginSql }
238+ ${ isReplicationRoleSql }
239+ ${ canBypassRlsSql }
240+ ${ connectionLimitSql }
241+ ${ passwordSql }
242+ ${ validUntilSql } ;
243+ ${ nameSql }
244+ COMMIT;`
245+ }
246+ const dropRoleSqlize = ( name : string ) => {
247+ return `DROP ROLE "${ name } "`
248+ }
122249const removeSystemSchemas = ( data : Roles . Role [ ] ) => {
123250 return data . map ( ( role ) => {
124251 let grants = role . grants . filter ( ( x ) => ! DEFAULT_SYSTEM_SCHEMAS . includes ( x . schema ) )
0 commit comments