Skip to content

Commit 78bd90d

Browse files
committed
Add custom view endpoints, service and repo
1 parent 4f523bb commit 78bd90d

File tree

11 files changed

+516
-49
lines changed

11 files changed

+516
-49
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Permissions from '../../security/permissions'
2+
import track from '../../segment/track'
3+
import CustomViewService from '../../services/customViewService'
4+
import PermissionChecker from '../../services/user/permissionChecker'
5+
6+
/**
7+
* POST /tenant/{tenantId}/customview
8+
* @summary Create a custom view
9+
* @tag CustomViews
10+
* @security Bearer
11+
* @description Create a custom view
12+
* @pathParam {string} tenantId - Your workspace/tenant ID
13+
* @bodyContent {CustomViewInput} application/json
14+
* @response 200 - Ok
15+
* @responseContent {CustomView} 200.application/json
16+
* @responseExample {CustomViewCreate} 200.application/json.CustomView
17+
* @response 401 - Unauthorized
18+
* @response 404 - Not found
19+
* @response 429 - Too many requests
20+
*/
21+
export default async (req, res) => {
22+
new PermissionChecker(req).validateHas(Permissions.values.customViewCreate)
23+
24+
const payload = await new CustomViewService(req).create(req.body)
25+
26+
track('Custom view Manually Created', { ...payload }, { ...req })
27+
28+
await req.responseHandler.success(req, res, payload)
29+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Permissions from '../../security/permissions'
2+
import CustomViewService from '../../services/customViewService'
3+
import PermissionChecker from '../../services/user/permissionChecker'
4+
5+
/**
6+
* DELETE /tenant/{tenantId}/customview/{id}
7+
* @summary Delete an custom view
8+
* @tag CustomViews
9+
* @security Bearer
10+
* @description Delete a custom view given an ID
11+
* @pathParam {string} tenantId - Your workspace/tenant ID
12+
* @pathParam {string} id - The ID of the custom view
13+
* @response 200 - Ok
14+
* @response 401 - Unauthorized
15+
* @response 404 - Not found
16+
* @response 429 - Too many requests
17+
*/
18+
export default async (req, res) => {
19+
new PermissionChecker(req).validateHas(Permissions.values.customViewDestroy)
20+
21+
await new CustomViewService(req).destroyAll(req.query.ids)
22+
23+
const payload = true
24+
25+
await req.responseHandler.success(req, res, payload)
26+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import Permissions from '../../security/permissions'
2+
import CustomViewService from '../../services/customViewService'
3+
import PermissionChecker from '../../services/user/permissionChecker'
4+
import track from '../../segment/track'
5+
6+
/**
7+
* POST /tenant/{tenantId}/customview/query
8+
* @summary Query custom views
9+
* @tag CustomViews
10+
* @security Bearer
11+
* @description Query custom views. It accepts filters and sorting options
12+
* @pathParam {string} tenantId - Your workspace/tenant ID
13+
* @bodyContent {CustomViewQuery} application/json
14+
* @response 200 - Ok
15+
* @responseContent {CustomViewList} 200.application/json
16+
* @responseExample {CustomViewList} 200.application/json.CustomView
17+
* @response 401 - Unauthorized
18+
* @response 404 - Not found
19+
* @response 429 - Too many requests
20+
*/
21+
export default async (req, res) => {
22+
new PermissionChecker(req).validateHas(Permissions.values.activityRead)
23+
24+
const payload = await new CustomViewService(req).query(req.body)
25+
26+
if (req.query.filter && Object.keys(req.query.filter).length > 0) {
27+
track('Custom views Fitler', { ...payload }, { ...req })
28+
}
29+
30+
await req.responseHandler.success(req, res, payload)
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Permissions from '../../security/permissions'
2+
import CustomViewService from '../../services/customViewService'
3+
import PermissionChecker from '../../services/user/permissionChecker'
4+
5+
/**
6+
* PUT /tenant/{tenantId}/customview/{id}
7+
* @summary Update an custom view
8+
* @tag CustomViews
9+
* @security Bearer
10+
* @description Update an custom view given an ID.
11+
* @pathParam {string} tenantId - Your workspace/tenant ID
12+
* @pathParam {string} id - The ID of the custom view
13+
* @bodyContent {CustomViewUpsertInput} application/json
14+
* @response 200 - Ok
15+
* @responseContent {CustomView} 200.application/json
16+
* @responseExample {CustomViewFind} 200.application/json.CustomView
17+
* @response 401 - Unauthorized
18+
* @response 404 - Not found
19+
* @response 429 - Too many requests
20+
*/
21+
export default async (req, res) => {
22+
new PermissionChecker(req).validateHas(Permissions.values.customViewEdit)
23+
24+
const payload = await new CustomViewService(req).update(req.params.id, req.body)
25+
26+
await req.responseHandler.success(req, res, payload)
27+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { safeWrap } from '../../middlewares/errorMiddleware'
2+
3+
export default (app) => {
4+
app.post(`/tenant/:tenantId/customview`, safeWrap(require('./customViewCreate').default))
5+
app.put(`/tenant/:tenantId/customview/:id`, safeWrap(require('./customViewUpdate').default))
6+
app.delete(`/tenant/:tenantId/customview`, safeWrap(require('./customViewDestroy').default))
7+
app.get(`/tenant/:tenantId/customview`, safeWrap(require('./customViewList').default))
8+
}

backend/src/database/migrations/V1695657964__customViews.sql

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@ create table "customViews" (
55
name varchar(255) not null check (name <> ''),
66
visibility "customViewVisibility" not null,
77
config jsonb default '{}',
8-
placement varchar(255) check (placement in ('member', 'organization', 'activity', 'conversation')),
8+
placement varchar(255)[] check (placement <@ ARRAY['members', 'organizations', 'activities', 'conversations']),
9+
"tenantId" uuid references "tenants"(id) on delete cascade,
10+
"createdById" uuid references "members"(id),
911
"updatedById" uuid references "members"(id),
1012
"deletedById" uuid references "members"(id),
11-
"updatedAt" timestamp,
12-
"deletedAt" timestamp
13+
"createdAt" timestamp with time zone not null default now(),
14+
"updatedAt" timestamp with time zone,
15+
"deletedAt" timestamp with time zone,
1316
);
1417

1518
create table "customViewOrders" (
1619
"order" integer not null default 0,
1720
"customViewId" uuid not null references "customViews"(id) on delete cascade,
18-
"memberId" uuid not null references "members"(id) on delete cascade
21+
"memberId" uuid not null references "members"(id) on delete cascade,
22+
"deletedAt" timestamp with time zone,
1923
);

backend/src/database/models/customView.ts

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,68 @@ import { DataTypes } from 'sequelize'
22
import { CustomViewVisibility } from '@crowd/types'
33

44
export default (sequelize) => {
5-
const customView = sequelize.define('customView', {
6-
id: {
7-
type: DataTypes.UUID,
8-
defaultValue: DataTypes.UUIDV4,
9-
primaryKey: true,
10-
},
11-
name: {
12-
type: DataTypes.STRING,
13-
allowNull: false,
14-
validate: {
15-
notEmpty: true,
5+
const customView = sequelize.define(
6+
'customView',
7+
{
8+
id: {
9+
type: DataTypes.UUID,
10+
defaultValue: DataTypes.UUIDV4,
11+
primaryKey: true,
1612
},
17-
},
18-
visibility: {
19-
type: DataTypes.ENUM,
20-
values: Object.values(CustomViewVisibility),
21-
allowNull: false,
22-
},
23-
config: {
24-
type: DataTypes.JSONB,
25-
defaultValue: {},
26-
},
27-
placement: {
28-
type: DataTypes.STRING,
29-
validate: {
30-
isIn: [['member', 'organization', 'activity', 'conversation']],
13+
name: {
14+
type: DataTypes.STRING,
15+
allowNull: false,
16+
validate: {
17+
notEmpty: true,
18+
},
19+
},
20+
visibility: {
21+
type: DataTypes.ENUM,
22+
values: Object.values(CustomViewVisibility),
23+
allowNull: false,
24+
},
25+
config: {
26+
type: DataTypes.JSONB,
27+
defaultValue: {},
28+
},
29+
placement: {
30+
type: DataTypes.ARRAY(DataTypes.STRING),
31+
validate: {
32+
isIn: [['members', 'organizations', 'activities', 'conversations']],
33+
},
3134
},
3235
},
33-
updatedById: {
34-
type: DataTypes.UUID,
35-
allowNull: true,
36-
},
37-
updatedAt: {
38-
type: DataTypes.DATE,
39-
},
40-
deletedById: {
41-
type: DataTypes.UUID,
42-
allowNull: true,
43-
},
44-
deletedAt: {
45-
type: DataTypes.DATE,
36+
{
37+
indexes: [
38+
{
39+
unqiue: true,
40+
fields: ['id', 'tenantId'],
41+
where: {
42+
deletedAt: null,
43+
},
44+
},
45+
],
46+
timestamps: true,
47+
paranoid: true,
4648
},
47-
})
49+
)
50+
51+
customView.associate = (models) => {
52+
models.customView.belongsTo(models.tenant, {
53+
as: 'tenantId',
54+
foreignKey: {
55+
allowNull: false,
56+
},
57+
})
58+
59+
models.customView.belongsTo(models.member, {
60+
as: 'createdById',
61+
})
62+
63+
models.customView.belongsTo(models.member, {
64+
as: 'updatedById',
65+
})
66+
}
4867

4968
return customView
5069
}

backend/src/database/models/customViewOrder.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
import { DataTypes } from 'sequelize'
22

33
export default (sequelize) => {
4-
const customViewOrder = sequelize.define('customViewOrder', {
5-
order: {
6-
type: DataTypes.INTEGER,
7-
allowNull: false,
8-
defaultValue: 0,
4+
const customViewOrder = sequelize.define(
5+
'customViewOrder',
6+
{
7+
order: {
8+
type: DataTypes.INTEGER,
9+
allowNull: false,
10+
defaultValue: 0,
11+
},
12+
},
13+
{
14+
indexes: [
15+
{
16+
where: {
17+
deletedAt: null,
18+
},
19+
},
20+
],
21+
paranoid: true,
922
},
10-
})
23+
)
1124

1225
customViewOrder.associate = (models) => {
1326
customViewOrder.belongsTo(models.customView, {

0 commit comments

Comments
 (0)