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

feat(condo): DOMA-10773 sendB2BAppPushMessage mutation and pass ticket created message #5667

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4ce0cfe
feat(condo): DOMA-10773 add types B2B_APP_MESSAGE_PUSH_TYPE PASS_TICK…
nomerdvadcatpyat Dec 16, 2024
9ac2cc1
feat(condo): DOMA-10773 add base sendB2BAppPushMessage mutation
nomerdvadcatpyat Dec 17, 2024
e3f2b61
feat(condo): DOMA-10773 added checks for sendB2BAppPushMessage
nomerdvadcatpyat Dec 18, 2024
de4ebfd
feat(condo): DOMA-10773 added tests
nomerdvadcatpyat Dec 19, 2024
c9fbd70
feat(condo): DOMA-10773 rename B2CAppMessageSetting to AppMessageSett…
nomerdvadcatpyat Dec 19, 2024
ee1dd60
feat(condo): DOMA-10773 add tests for AppMessageSetting
nomerdvadcatpyat Dec 23, 2024
3c5a55f
feat(condo): DOMA-10773 add delay and blacklisted logic in SendB2BApp…
nomerdvadcatpyat Dec 23, 2024
82e50b7
feat(pass): DOMA-10773 update pass submodule
nomerdvadcatpyat Dec 24, 2024
c09de9c
feat(condo): DOMA-10773 migration with drop B2CAppMessageSetting and …
nomerdvadcatpyat Dec 24, 2024
553f77a
feat(condo): DOMA-10773 migrate data in migration
nomerdvadcatpyat Dec 24, 2024
9c320e0
feat(pass): DOMA-10773 update message templates
nomerdvadcatpyat Dec 24, 2024
5360519
feat(condo): DOMA-10773 update B2BAppAccessRightSet test
nomerdvadcatpyat Dec 24, 2024
874e355
feat(condo): DOMA-10773 fix push titles test
nomerdvadcatpyat Dec 25, 2024
f9e2187
feat(condo): DOMA-10773 add title to B2B app custom push message
nomerdvadcatpyat Dec 25, 2024
14f545d
fix(condo): DOMA-10773 added if (not) exists statements to migration
nomerdvadcatpyat Dec 28, 2024
f176861
refactor(condo): DOMA-10773 rebased, recreated migration, updated pas…
nomerdvadcatpyat Jan 26, 2025
0e3a2e4
refactor(condo): DOMA-10773 used getEmployedOrganizationsByPermission…
nomerdvadcatpyat Jan 27, 2025
48436e1
refactor(condo): DOMA-10773 check b2bAppRole existence in AppMessageS…
nomerdvadcatpyat Jan 27, 2025
7e302a6
feat(condo): DOMA-10773 added B2BAppRole check in SendB2BAppPushMesag…
nomerdvadcatpyat Jan 28, 2025
87a851b
chore(condo): DOMA-10773 update schema
nomerdvadcatpyat Jan 28, 2025
02cf56c
feat(condo): DOMA-10773 update translations
nomerdvadcatpyat Jan 28, 2025
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
7 changes: 7 additions & 0 deletions apps/condo/bin/fix-database-migration-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,13 @@ COMMIT;
--
DROP TABLE "ExternalReport" CASCADE;
DROP TABLE "ExternalReportHistoryRecord" CASCADE;

--
-- 20250126181755-0446_auto_20250126_1318.js Rename B2CAppMessageSetting to AppMessageSetting
--
DROP TABLE "B2CAppMessageSetting" CASCADE;
DROP TABLE "B2CAppMessageSettingHistoryRecord" CASCADE;

COMMIT;
`))
}
Expand Down
59 changes: 59 additions & 0 deletions apps/condo/domains/miniapp/access/AppMessageSetting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Generated by `createschema miniapp.AppMessageSettings 'app?:Relationship:B2CApp:CASCADE; blockReason:Text; blockedNotificationTypes:Text; throttlingTime:Integer;'`
*/

const uniq = require('lodash/uniq')

const { throwAuthenticationError } = require('@open-condo/keystone/apolloErrorFormatter')
const { find } = require('@open-condo/keystone/schema')

const { STAFF } = require('@condo/domains/user/constants/common')


async function canReadAppMessageSetting ({ authentication: { item: user }, context }) {
if (!user) return throwAuthenticationError()
if (user.deletedAt) return false
if (user.isAdmin || user.isSupport) return {}

if (user.type === STAFF) {
const userEmployees = await find('OrganizationEmployee', {
deletedAt: null,
organization: { deletedAt: null },
role: { deletedAt: null },
user: { id: user.id },
isBlocked: false,
isRejected: false,
})
const employeeRoleIds = userEmployees.map(employee => employee.role)
const b2bAppRoles = await find('B2BAppRole', {
deletedAt: null,
role: { id_in: employeeRoleIds },
})
const b2bAppIds = uniq(b2bAppRoles.map(b2bAppRole => b2bAppRole.app))

return {
b2bApp: {
id_in: b2bAppIds,
},
}
}

return false
}

async function canManageAppMessageSetting ({ authentication: { item: user } }) {
if (!user) return throwAuthenticationError()
if (user.deletedAt) return false
if (user.isAdmin || user.isSupport) return true

return false
}

/*
Rules are logical functions that used for list access, and may return a boolean (meaning
all or no items are available) or a set of filters that limit the available items.
*/
module.exports = {
canReadAppMessageSetting,
canManageAppMessageSetting,
}
31 changes: 0 additions & 31 deletions apps/condo/domains/miniapp/access/B2CAppMessageSetting.js

This file was deleted.

23 changes: 23 additions & 0 deletions apps/condo/domains/miniapp/access/SendB2BAppPushMessageService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Generated by `createservice miniapp.SendB2BAppPushMessageService '--type=mutations'`
*/
const { throwAuthenticationError } = require('@open-condo/keystone/apolloErrorFormatter')

const { SERVICE } = require('@condo/domains/user/constants/common')

async function canSendB2BAppPushMessage (args) {
const { authentication: { item: user } } = args

if (!user) return throwAuthenticationError()
if (user.deletedAt) return false

return user.type === SERVICE
}

/*
Rules are logical functions that used for list access, and may return a boolean (meaning
all or no items are available) or a set of filters that limit the available items.
*/
module.exports = {
canSendB2BAppPushMessage,
}
6 changes: 6 additions & 0 deletions apps/condo/domains/miniapp/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ const NEWS_SHARING_PUSH_NOTIFICATION_SETTINGS = {
DISABLED: 'DISABLED',
}

const DEFAULT_NOTIFICATIONS_IN_WINDOW_COUNT = 1
const DEFAULT_NOTIFICATION_WINDOW_DURATION_IN_SECONDS = 3600

const ACCESS_RIGHT_SET_GLOBAL_TYPE = 'GLOBAL'
const ACCESS_RIGHT_SET_SCOPED_TYPE = 'SCOPED'

Expand Down Expand Up @@ -201,4 +204,7 @@ module.exports = {

ACCESS_TOKEN_SESSION_ID_PREFIX,
ACCESS_TOKEN_UPDATE_MANY_CHUNK_SIZE,

DEFAULT_NOTIFICATIONS_IN_WINDOW_COUNT,
DEFAULT_NOTIFICATION_WINDOW_DURATION_IN_SECONDS,
}
13 changes: 10 additions & 3 deletions apps/condo/domains/miniapp/gql.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,21 @@ const MessageAppBlackList = generateGqlQueries('MessageAppBlackList', MESSAGE_AP
const B2B_APP_ACCESS_RIGHT_SET_FIELDS = `{ app { id } type name ${B2B_ACCESSES_LISTS_FIELDS} ${B2B_ACCESSES_SERVICES_FIELDS} ${COMMON_FIELDS} }`
const B2BAppAccessRightSet = generateGqlQueries('B2BAppAccessRightSet', B2B_APP_ACCESS_RIGHT_SET_FIELDS)

const B2C_APP_MESSAGE_SETTINGS_FIELDS = `{ app { id } isBlacklisted blockReason type notificationWindowSize numberOfNotificationInWindow ${COMMON_FIELDS} }`
const B2CAppMessageSetting = generateGqlQueries('B2CAppMessageSetting', B2C_APP_MESSAGE_SETTINGS_FIELDS)
const APP_MESSAGE_SETTINGS_FIELDS = `{ b2cApp { id } b2bApp { id } isBlacklisted blockReason type notificationWindowSize numberOfNotificationInWindow ${COMMON_FIELDS} }`
const AppMessageSetting = generateGqlQueries('AppMessageSetting', APP_MESSAGE_SETTINGS_FIELDS)

const B2B_ACCESS_TOKEN_FIELDS = `{ token user { id } context { id app { id name } organization { id name } } rightSet { id name } expiresAt ${COMMON_FIELDS} }`
const B2BAccessToken = generateGqlQueries('B2BAccessToken', B2B_ACCESS_TOKEN_FIELDS)
const B2BAccessTokenAdmin = generateGqlQueries('B2BAccessToken', `{ sessionId token user { id } context { id app { id name } organization { id name } } rightSet { id name } expiresAt ${COMMON_FIELDS} }`)
const B2BAccessTokenReadonly = generateGqlQueries('B2BAccessToken', `{ context { id app { id name } organization { id name } } expiresAt ${COMMON_FIELDS} }`)
const B2BAccessTokenReadonlyAdmin = generateGqlQueries('B2BAccessToken', `{ sessionId context { id app { id name } organization { id name } } expiresAt ${COMMON_FIELDS} }`)

const SEND_B2B_APP_PUSH_MESSAGE_MUTATION = gql`
mutation sendB2BAppPushMessage ($data: SendB2BAppPushMessageInput!) {
result: sendB2BAppPushMessage(data: $data) { id status }
}
`

/* AUTOGENERATE MARKER <CONST> */

module.exports = {
Expand All @@ -103,10 +109,11 @@ module.exports = {
B2CAppProperty,
MessageAppBlackList,
B2BAppNewsSharingConfig,
B2CAppMessageSetting,
B2BAccessToken,
B2BAccessTokenAdmin,
B2BAccessTokenReadonly,
B2BAccessTokenReadonlyAdmin,
AppMessageSetting,
SEND_B2B_APP_PUSH_MESSAGE_MUTATION,
/* AUTOGENERATE MARKER <EXPORTS> */
}
109 changes: 109 additions & 0 deletions apps/condo/domains/miniapp/schema/AppMessageSetting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Generated by `createschema miniapp.AppMessageSettings 'app?:Relationship:B2CApp:CASCADE; blockReason:Text; blockedNotificationTypes:Text; throttlingTime:Integer;'`
*/

const { GQLError, GQLErrorCode: { BAD_USER_INPUT } } = require('@open-condo/keystone/errors')
const { historical, versioned, uuided, tracked, softDeleted, dvAndSender } = require('@open-condo/keystone/plugins')
const { GQLListSchema } = require('@open-condo/keystone/schema')

const { OPERATION_FORBIDDEN } = require('@condo/domains/common/constants/errors')
const access = require('@condo/domains/miniapp/access/AppMessageSetting')
const { getMessageTypeField } = require('@condo/domains/notification/schema/fields/MessageType')


const ERRORS = {
APP_MESSAGE_SETTING_MUST_HAVE_ONLY_B2B_OR_B2C_APP_FIELD: {
code: BAD_USER_INPUT,
type: OPERATION_FORBIDDEN,
message: 'AppMessageSetting must have either b2bApp or b2cApp field',
},
}

const AppMessageSetting = new GQLListSchema('AppMessageSetting', {
schemaDoc: 'Configuration of sending push notifications for specific miniapps.' +
'Used to block certain types of push notifications and control throttling of notifications of a certain miniapp',
fields: {

b2bApp: {
schemaDoc: 'Link to B2BApp to which this config applies',
type: 'Relationship',
ref: 'B2BApp',
isRequired: false,
kmigratorOptions: { null: true, on_delete: 'models.CASCADE' },
},

b2cApp: {
schemaDoc: 'Link to B2CApp to which this config applies',
type: 'Relationship',
ref: 'B2CApp',
isRequired: false,
kmigratorOptions: { null: true, on_delete: 'models.CASCADE' },
},

blockReason: {
schemaDoc: 'Reason for blocking messages with types from type',
type: 'Text',
},

isBlacklisted: {
schemaDoc: 'Is message type in black list for this miniapp',
type: 'Checkbox',
isRequired: true,
defaultValue: false,
},

type: getMessageTypeField({
isRequired: true,
schemaDoc: 'The type of message we want to configure',
}),

notificationWindowSize: {
schemaDoc: 'Time window for sending push notifications in seconds',
type: 'Integer',
},

numberOfNotificationInWindow: {
schemaDoc: 'The number of notifications that can be sent in one time window in seconds',
type: 'Integer',
},

},
hooks: {
validateInput: ({ context, existingItem, resolvedData }) => {
const newItem = { ...existingItem, ...resolvedData }

if ((!newItem.b2cApp && !newItem.b2bApp) || (newItem.b2cApp && newItem.b2bApp)) {
throw new GQLError(ERRORS.APP_MESSAGE_SETTING_MUST_HAVE_ONLY_B2B_OR_B2C_APP_FIELD, context)
}
},
},
plugins: [uuided(), versioned(), tracked(), softDeleted(), dvAndSender(), historical()],
access: {
read: access.canReadAppMessageSetting,
create: access.canManageAppMessageSetting,
update: access.canManageAppMessageSetting,
delete: false,
auth: true,
},
kmigratorOptions: {
constraints: [
{
type: 'models.UniqueConstraint',
fields: ['b2cApp', 'type'],
condition: 'Q(deletedAt__isnull=True)',
name: 'app_message_setting_unique_b2c_app_and_type',
},
{
type: 'models.UniqueConstraint',
fields: ['b2bApp', 'type'],
condition: 'Q(deletedAt__isnull=True)',
name: 'app_message_setting_unique_b2b_app_and_type',
},
],
},
})

module.exports = {
AppMessageSetting,
ERRORS,
}
Loading
Loading