Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into 15959
Browse files Browse the repository at this point in the history
  • Loading branch information
Jxio committed May 23, 2024
2 parents fdbb35d + e541b85 commit 32aafc7
Show file tree
Hide file tree
Showing 34 changed files with 317 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Add in new table for account mailer for pubsub message processing.
Revision ID: b3a741249edc
Revises: e2d1d6417607
Create Date: 2024-05-15 14:52:45.780399
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'b3a741249edc'
down_revision = 'e2d1d6417607'
branch_labels = None
depends_on = None


def upgrade():
op.create_table('pubsub_message_processing',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('cloud_event_id', sa.String(length=250), nullable=False),
sa.Column('created', sa.DateTime(), nullable=True),
sa.Column('message_type', sa.String(length=250), nullable=False),
sa.Column('processed', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_pubsub_message_processing_id'), 'pubsub_message_processing', ['id'], unique=False)


def downgrade():
op.drop_index(op.f('ix_pubsub_message_processing_id'), table_name='pubsub_message_processing')
op.drop_table('pubsub_message_processing')
2 changes: 1 addition & 1 deletion auth-api/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ python-jose==3.3.0
python-memcached==1.62
pytz==2024.1
redis==5.0.4
requests==2.31.0
requests==2.32.0
rsa==4.9
semver==3.0.2
sentry-sdk==2.0.1
Expand Down
1 change: 1 addition & 0 deletions auth-api/src/auth_api/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
from .product_subscription import ProductSubscription
from .product_subscriptions_status import ProductSubscriptionsStatus
from .product_type_code import ProductTypeCode
from .pubsub_message_processing import PubSubMessageProcessing
from .suspension_reason_code import SuspensionReasonCode
from .task import Task
from .user import User
Expand Down
2 changes: 1 addition & 1 deletion auth-api/src/auth_api/models/membership.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Membership(VersionedModel): # pylint: disable=too-few-public-methods # Te
user = relationship('User', foreign_keys=[user_id], lazy='select')
org = relationship('Org', foreign_keys=[org_id], lazy='select')

def __init__(self, **kwargs):
def __init__(self, **kwargs): # pylint: disable=super-init-not-called
"""Initialize a new membership."""
self.org_id = kwargs.get('org_id')
self.user_id = kwargs.get('user_id')
Expand Down
32 changes: 32 additions & 0 deletions auth-api/src/auth_api/models/pubsub_message_processing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""This model manages pubsub message processing.
NOTE: Only use this when it's not possible to use other indicators to track message processing.
Currently used by the account-mailer / auth-queue. This prevents duplicates.
"""
import datetime as dt
import pytz

from sqlalchemy import Column, DateTime, Integer, String
from .db import db


class PubSubMessageProcessing(db.Model):
"""PubSub Message Processing for cloud event messages."""

__tablename__ = 'pubsub_message_processing'

id = Column(Integer, index=True, primary_key=True)
cloud_event_id = Column(String(250), nullable=False)
created = Column(DateTime, default=dt.datetime.now(pytz.utc))
message_type = Column(String(250), nullable=False)
processed = Column(DateTime, nullable=True)

@classmethod
def find_by_id(cls, identifier):
"""Find a pubsub message processing by id."""
return cls.query.filter_by(id=identifier).one_or_none()

@classmethod
def find_by_cloud_event_id_and_type(cls, cloud_event_id, message_type):
"""Find a pubsub message processing for cloud event id and type."""
return cls.query.filter_by(cloud_event_id=cloud_event_id, message_type=message_type).one_or_none()
1 change: 1 addition & 0 deletions auth-api/src/auth_api/services/authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ def check_auth(**kwargs):
if product_code_in_jwt == 'ALL': # Product code for super admin service account (sbc-auth-admin)
return

auth = None
if business_identifier:
auth = Authorization.get_user_authorizations_for_entity(business_identifier)
elif org_identifier:
Expand Down
2 changes: 1 addition & 1 deletion auth-api/src/auth_api/services/gcp_queue/gcp_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def publisher(self):
"""Returns the publisher."""
if not self._publisher and self.credentials_pub:
self._publisher = pubsub_v1.PublisherClient(credentials=self.credentials_pub)
else:
if not self._publisher:
self._publisher = pubsub_v1.PublisherClient()
return self._publisher

Expand Down
6 changes: 3 additions & 3 deletions auth-api/src/auth_api/services/membership.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ def send_notification_to_member(self, origin_url, notification_type):
notification_type_for_mailer = ''
data = {}
if notification_type == NotificationType.ROLE_CHANGED.value:
notification_type_for_mailer = 'roleChangedNotification'
notification_type_for_mailer = QueueMessageTypes.ROLE_CHANGED_NOTIFICATION.value
data = {
'accountId': org_id,
'emailAddresses': recipient,
Expand All @@ -181,9 +181,9 @@ def send_notification_to_member(self, origin_url, notification_type):
# TODO how to check properly if user is bceid user
is_bceid_user = self._model.user.username.find('@bceid') > 0
if is_bceid_user:
notification_type_for_mailer = 'membershipApprovedNotificationForBceid'
notification_type_for_mailer = QueueMessageTypes.MEMBERSHIP_APPROVED_NOTIFICATION_FOR_BCEID.value
else:
notification_type_for_mailer = 'membershipApprovedNotification'
notification_type_for_mailer = QueueMessageTypes.MEMBERSHIP_APPROVED_NOTIFICATION.value

data = {
'accountId': org_id,
Expand Down
4 changes: 2 additions & 2 deletions auth-api/src/auth_api/services/org.py
Original file line number Diff line number Diff line change
Expand Up @@ -878,9 +878,9 @@ def send_approved_rejected_notification(receipt_admin_emails, org_name, org_id,
current_app.logger.debug('<send_approved_rejected_notification')

if org_status == OrgStatus.ACTIVE.value:
notification_type = QueueMessageTypes.NON_BCSC_ORG_APPROVED.value
notification_type = QueueMessageTypes.NON_BCSC_ORG_APPROVED_NOTIFICATION.value
elif org_status == OrgStatus.REJECTED.value:
notification_type = QueueMessageTypes.NON_BCSC_ORG_REJECTED.value
notification_type = QueueMessageTypes.NON_BCSC_ORG_REJECTED_NOTIFICATION.value
else:
return # Don't send mail for any other status change
app_url = f"{origin_url}/{current_app.config.get('AUTH_WEB_TOKEN_CONFIRM_PATH')}"
Expand Down
1 change: 1 addition & 0 deletions auth-api/src/auth_api/services/validators/payment_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def validate(is_fatal=False, **kwargs) -> ValidatorResponse:
OrgType.SBC_STAFF: non_ejv_payment_methods,
OrgType.STAFF: non_ejv_payment_methods,
}
payment_type = None
if access_type == AccessType.GOVM.value:
payment_type = PaymentMethod.EJV.value
elif selected_payment_method:
Expand Down
2 changes: 1 addition & 1 deletion auth-api/src/auth_api/utils/custom_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from sqlalchemy import String, func


class CustomQuery(BaseQuery):
class CustomQuery(BaseQuery): # pylint: disable=too-few-public-methods
"""Custom Query class to extend the base query class for helper functionality."""

def filter_conditionally(self, search_criteria, model_attribute, is_like: bool = False):
Expand Down
6 changes: 3 additions & 3 deletions auth-api/tests/unit/services/test_authorization.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,8 @@ def test_check_auth_staff_path(session, monkeypatch, test_desc, test_expect, add
'test_desc,test_expect,additional_kwargs,is_org_member,is_entity_affiliated,product_code_in_jwt',
[
(
'Test UnboundLocalError when no role checks provided in kwargs, and no org_id or business_identifier.',
pytest.raises(UnboundLocalError), {}, False, False, ProductCode.BUSINESS.value
'Test 403 when no role checks provided in kwargs, and no org_id or business_identifier.',
pytest.raises(Forbidden), {}, False, False, ProductCode.BUSINESS.value
),
(
'Test OK when no role checks provided in kwargs, but has ALL product in jwt. (bypass all checks).',
Expand Down Expand Up @@ -359,7 +359,7 @@ def test_check_auth_system_path(session, monkeypatch, test_desc, test_expect, ad
'test_desc,test_expect,additional_kwargs,is_org_member,is_entity_affiliated',
[
(
'Test UnboundLocalError when no role checks provided in kwargs.',
'Test UnboundLocalError (403) when no role checks provided in kwargs.',
pytest.raises(UnboundLocalError), {}, False, False
),
(
Expand Down
6 changes: 3 additions & 3 deletions auth-web/src/components/auth/staff/DissolutionSchedule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ export default defineComponent({
setup () {
const state = reactive({
menu: false,
numberOfBusinessesEdit: 0,
numberOfBusinessesNonEdit: 0,
numberOfBusinessesEdit: -1,
numberOfBusinessesNonEdit: -1,
numberOfBusinessesRef: null,
isEdit: false,
isSaving: false
Expand All @@ -135,7 +135,7 @@ export default defineComponent({
await staffStore.getDissolutionConfigurations()
// Get the batch size current value (number of businesses to be dissolved per job run)
const numDissolutions = staffStore.involuntaryDissolutionConfigurations.configurations.find(
const numDissolutions = staffStore.involuntaryDissolutionConfigurations?.configurations?.find(
config => config.name === 'NUM_DISSOLUTIONS_ALLOWED').value
state.numberOfBusinessesNonEdit = parseInt(numDissolutions)
})
Expand Down
8 changes: 8 additions & 0 deletions auth-web/src/models/Staff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,11 @@ export interface InvoluntaryDissolutionConfigurationIF {
export interface Configurations {
configurations: InvoluntaryDissolutionConfigurationIF[]
}

export interface DissolutionStatistics {
data: { eligibleCount: number }
}

export interface SafeListEmailsRequestBody {
email: string[]
}
22 changes: 21 additions & 1 deletion auth-web/src/services/staff.services.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { AccountType, Configurations, ProductCode, Products, ProductsRequestBody } from '@/models/Staff'
import {
AccountType,
Configurations,
DissolutionStatistics,
ProductCode,
Products,
ProductsRequestBody,
SafeListEmailsRequestBody
} from '@/models/Staff'
import { OrgFilterParams, OrgList, Organizations } from '@/models/Organization'
import { AxiosResponse } from 'axios'
import ConfigHelper from '@/util/config-helper'
Expand Down Expand Up @@ -53,7 +61,19 @@ export default class StaffService {
return axios.get(`${ConfigHelper.getLegalAPIV2Url()}/admin/configurations`)
}

static async getDissolutionStatistics (): Promise<AxiosResponse<DissolutionStatistics>> {
return axios.get(`${ConfigHelper.getLegalAPIV2Url()}/admin/dissolutions/statistics`)
}

static async updateInvoluntaryDissolutionConfigurations (configurations: Configurations): Promise<AxiosResponse<Configurations>> {
return axios.put(`${ConfigHelper.getLegalAPIV2Url()}/admin/configurations`, configurations)
}

static async deleteSafeEmail (email: string): Promise<AxiosResponse<SafeEmail[]>> {
return axios.delete(`${ConfigHelper.getNotifiyAPIUrl()}/safe_list/${email}`)
}

static async addSafeEmail (safeListEmailsRequestBody: SafeListEmailsRequestBody): Promise<AxiosResponse<SafeEmail[]>> {
return axios.post(`${ConfigHelper.getNotifiyAPIUrl()}/safe_list`, safeListEmailsRequestBody)
}
}
18 changes: 12 additions & 6 deletions auth-web/src/stores/staff.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AccountStatus, AffidavitStatus, TaskAction, TaskRelationshipStatus, TaskRelationshipType, TaskType } from '@/util/constants'
import { AccountType, Configurations, GLCode, ProductCode } from '@/models/Staff'
import { AccountType, Configurations, DissolutionStatistics, GLCode, ProductCode } from '@/models/Staff'
import { MembershipType, OrgFilterParams, Organization } from '@/models/Organization'
import { SyncAccountPayload, Task } from '@/models/Task'
import { computed, reactive, toRefs } from '@vue/composition-api'
Expand All @@ -25,6 +25,7 @@ export const useStaffStore = defineStore('staff', () => {
accountUnderReviewAdminContact: {} as Contact,
accountUnderReviewAffidavitInfo: {} as AffidavitInformation,
activeStaffOrgs: [] as Organization[],
dissolutionStatistics: {} as DissolutionStatistics,
involuntaryDissolutionConfigurations: {} as Configurations,
pendingInvitationOrgs: [] as Organization[],
pendingStaffOrgs: [] as Organization[],
Expand All @@ -42,6 +43,7 @@ export const useStaffStore = defineStore('staff', () => {
state.accountUnderReviewAdminContact = {} as Contact
state.accountUnderReviewAffidavitInfo = {} as AffidavitInformation
state.activeStaffOrgs = [] as Organization[]
state.dissolutionStatistics = {} as DissolutionStatistics
state.involuntaryDissolutionConfigurations = {} as Configurations
state.pendingInvitationOrgs = [] as Organization[]
state.pendingStaffOrgs = [] as Organization[]
Expand Down Expand Up @@ -81,12 +83,15 @@ export const useStaffStore = defineStore('staff', () => {
}

/** Get the involuntary dissolution configurations array from Legal API. */
async function getDissolutionConfigurations (): Promise<Configurations> {
async function getDissolutionConfigurations (): Promise<void> {
const response = await StaffService.getInvoluntaryDissolutionConfigurations()
if (response?.data && response.status === 200) {
state.involuntaryDissolutionConfigurations = response.data
return response.data
}
if (response?.data && response.status === 200) state.involuntaryDissolutionConfigurations = response.data
}

/** Get the businesses dissolution statistics (businesses ready for D1 dissolution). */
async function getDissolutionStatistics (): Promise<void> {
const response = await StaffService.getDissolutionStatistics()
if (response?.data && response.status === 200) state.dissolutionStatistics = response.data
}

async function getAccountTypes (): Promise<AccountType[]> {
Expand Down Expand Up @@ -307,6 +312,7 @@ export const useStaffStore = defineStore('staff', () => {
deleteOrg,
getAccountTypes,
getDissolutionConfigurations,
getDissolutionStatistics,
getGLCode,
getGLCodeList,
getGLCodeFiling,
Expand Down
7 changes: 5 additions & 2 deletions auth-web/src/util/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,9 +660,12 @@ export enum CfsAccountStatus {

export enum InvoluntaryDissolutionConfigNames {
DISSOLUTIONS_ON_HOLD = 'DISSOLUTIONS_ON_HOLD',
DISSOLUTIONS_STAGE_1_SCHEDULE='DISSOLUTIONS_STAGE_1_SCHEDULE',
DISSOLUTIONS_STAGE_2_SCHEDULE='DISSOLUTIONS_STAGE_2_SCHEDULE',
DISSOLUTIONS_STAGE_3_SCHEDULE='DISSOLUTIONS_STAGE_3_SCHEDULE',
DISSOLUTIONS_SUMMARY_EMAIL = 'DISSOLUTIONS_SUMMARY_EMAIL',
MAX_DISSOLUTIONS_ALLOWED = 'MAX_DISSOLUTIONS_ALLOWED',
NUM_DISSOLUTIONS_ALLOWED = 'NUM_DISSOLUTIONS_ALLOWED',
NEW_DISSOLUTIONS_SCHEDULE = 'NEW_DISSOLUTIONS_SCHEDULE'
NUM_DISSOLUTIONS_ALLOWED = 'NUM_DISSOLUTIONS_ALLOWED'
}

export enum AccountType {
Expand Down
38 changes: 30 additions & 8 deletions auth-web/src/views/auth/staff/InvoluntaryDissolution.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
id="involuntary-dissolution"
class="view-container"
>
<!-- Spinner while waiting to grab the number of the businesses ready for D1 Dissolution -->
<v-fade-transition>
<div
v-if="isLoading"
class="loading-container"
>
<v-progress-circular
size="50"
width="5"
color="primary"
:indeterminate="isLoading"
/>
</div>
</v-fade-transition>
<div class="view-header flex-column">
<h1>
Staff Involuntary Dissolution Batch
Expand Down Expand Up @@ -55,9 +69,10 @@
</template>

<script lang="ts">
import { computed, defineComponent, onMounted } from '@vue/composition-api'
import { defineComponent, onMounted, reactive, toRefs } from '@vue/composition-api'
import { CardHeader } from '@/components'
import DissolutionSchedule from '@/components/auth/staff/DissolutionSchedule.vue'
import { useStaffStore } from '@/stores/staff'
export default defineComponent({
name: 'InvoluntaryDissolution',
Expand All @@ -66,16 +81,23 @@ export default defineComponent({
DissolutionSchedule
},
setup () {
onMounted(() => {})
const state = reactive({
businessesReadyforDissolutionNumber: -1,
isLoading: true
})
const staffStore = useStaffStore()
/**
* The number of B.C. businesses that are ready for D1 Dissolution.
* TODO: Change this once the BE is done.
*/
const businessesReadyforDissolutionNumber = computed(() => 0)
onMounted(async () => {
// Make the call to get the involuntary dissolutions statistics data and set it in store
await staffStore.getDissolutionStatistics()
state.businessesReadyforDissolutionNumber = staffStore.dissolutionStatistics?.data?.eligibleCount
// Hide spinner
state.isLoading = false
})
return {
businessesReadyforDissolutionNumber
...toRefs(state)
}
}
})
Expand Down
Loading

0 comments on commit 32aafc7

Please sign in to comment.