Skip to content

Commit

Permalink
Merge branch 'release-0.2.0' into fix/daniel-subtract-reserve-credits…
Browse files Browse the repository at this point in the history
…-1575
  • Loading branch information
dhaselhan authored Jan 9, 2025
2 parents d8f7b52 + 087a8bb commit 9a05f78
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 80 deletions.
55 changes: 34 additions & 21 deletions backend/lcfs/web/api/user/repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,31 +352,46 @@ async def create_user(
async def update_user(
self, user: UserProfile, user_update: UserCreateSchema
) -> None:
"""
Update an existing UserProfile with new data.
"""

# Extract incoming data from the Pydantic schema
user_data = user_update.model_dump()
updated_user_profile = UserProfile(**user_update.model_dump(exclude={"roles"}))
roles = user_data.pop("roles", {})
new_roles = user_data.pop("roles", {})

# Update basic fields directly
user.email = user_update.email
user.title = user_update.title
user.first_name = user_update.first_name
user.last_name = user_update.last_name
user.is_active = user_update.is_active
user.keycloak_email = user_update.keycloak_email
user.keycloak_username = user_update.keycloak_username
user.phone = user_update.phone
user.mobile_phone = user_update.mobile_phone

# Find the RoleEnum member corresponding to each role
new_roles = [
role_enum for role_enum in RoleEnum if role_enum.value.lower() in roles
]
new_role_enums = []
for role_str in new_roles:
try:
name_str = role_str.title()
role_enum = RoleEnum(name_str)
new_role_enums.append(role_enum)
except ValueError:
pass

# Create a set for faster membership checks
existing_roles_set = set(user.role_names)

# Update the user object with the new data
user.email = updated_user_profile.email
user.title = updated_user_profile.title
user.first_name = updated_user_profile.first_name
user.last_name = updated_user_profile.last_name
user.is_active = updated_user_profile.is_active
user.keycloak_email = updated_user_profile.keycloak_email
user.keycloak_username = updated_user_profile.keycloak_username
user.phone = updated_user_profile.phone
user.mobile_phone = updated_user_profile.mobile_phone

if user.organization:
await self.update_bceid_roles(user, new_roles, existing_roles_set)
# BCEID logic
await self.update_bceid_roles(user, new_role_enums, existing_roles_set)
else:
await self.update_idir_roles(user, new_roles, existing_roles_set)
# IDIR logic
await self.update_idir_roles(user, new_role_enums, existing_roles_set)

# Add the updated user to the session
self.db.add(user)
return user

Expand Down Expand Up @@ -672,9 +687,7 @@ async def create_login_history(self, user: UserProfile):
self.db.add(login_history)

@repo_handler
async def update_email(
self, user_profile_id: int, email: str
) -> UserProfile:
async def update_email(self, user_profile_id: int, email: str) -> UserProfile:
# Fetch the user profile
query = select(UserProfile).where(
UserProfile.user_profile_id == user_profile_id
Expand Down
5 changes: 4 additions & 1 deletion etl/nifi_scripts/compliance_report.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,9 @@ def prepareStatements(Connection conn) {
* @return Inserted compliance_report_id.
*/
def insertComplianceReport(PreparedStatement stmt, Map report, String groupUuid, int version, String supplementalInitiator, String reportingFrequency, Integer currentStatusId, String createUser, String updateUser) {
// Generate nickname based on version
def nickname = (version == 0) ? "Original Report" : "Supplemental Report ${version}"

stmt.setInt(1, report.compliance_period_id)
stmt.setInt(2, report.organization_id)

Expand All @@ -862,7 +865,7 @@ def insertComplianceReport(PreparedStatement stmt, Map report, String groupUuid,
stmt.setInt(5, version)
stmt.setObject(6, supplementalInitiator)
stmt.setString(7, reportingFrequency)
stmt.setString(8, report.nickname)
stmt.setString(8, nickname)
stmt.setString(9, report.supplemental_note)
stmt.setString(10, createUser)
stmt.setTimestamp(11, report.create_timestamp ?: Timestamp.valueOf("1970-01-01 00:00:00"))
Expand Down
88 changes: 74 additions & 14 deletions etl/nifi_scripts/user.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,83 @@ import groovy.json.JsonSlurper

log.warn('**** STARTING USER ETL ****')

// SQL query to extract user profiles
def userProfileQuery = """
SELECT id as user_profile_id,
keycloak_user_id,
COALESCE(NULLIF(email, ''), '[email protected]') as keycloak_email,
username as keycloak_username,
COALESCE(NULLIF(email, ''), '[email protected]') as email,
title,
phone,
cell_phone as mobile_phone,
first_name,
last_name,
is_active,
CASE WHEN organization_id = 1 THEN NULL ELSE organization_id END as organization_id
FROM public.user;
WITH ranked_users AS (
SELECT
u.id AS user_profile_id,
u.keycloak_user_id,
-- If external_username is empty or null, make it null for easier handling
CASE WHEN COALESCE(NULLIF(ucr.external_username, ''), NULL) IS NULL THEN NULL
ELSE ucr.external_username
END AS raw_external_username,
-- Use a window function to identify duplicates within each external_username group
ROW_NUMBER() OVER (
PARTITION BY COALESCE(NULLIF(ucr.external_username, ''), '___EMPTY___')
ORDER BY
CASE WHEN u.keycloak_user_id IS NOT NULL THEN 0 ELSE 1 END,
u.id
) AS occurrence,
COALESCE(NULLIF(ucr.keycloak_email, ''), u.email) AS keycloak_email,
COALESCE(NULLIF(u.email, ''), '') AS email,
u.title,
u.phone,
u.cell_phone AS mobile_phone,
u.first_name,
u.last_name,
u.is_active,
CASE WHEN u.organization_id = 1 THEN NULL ELSE u.organization_id END AS organization_id
FROM public.user u
LEFT JOIN user_creation_request ucr ON ucr.user_id = u.id
),
resolved_users AS (
SELECT
user_profile_id,
keycloak_user_id,
CASE
-- 1) No external_username => "FIXME<n>"
WHEN raw_external_username IS NULL THEN
CONCAT('FIXME', occurrence)
-- 2) Duplicate external_username => add "_<occurrence>"
WHEN occurrence > 1 THEN
CONCAT(raw_external_username, '_', occurrence)
-- 3) Unique or first occurrence => use raw_external_username
ELSE raw_external_username
END AS keycloak_username,
keycloak_email,
email,
title,
phone,
mobile_phone,
first_name,
last_name,
is_active,
organization_id
FROM ranked_users
)
SELECT
user_profile_id,
keycloak_user_id,
keycloak_username,
keycloak_email,
email,
title,
phone,
mobile_phone,
first_name,
last_name,
is_active,
organization_id
FROM resolved_users;
"""


// SQL query to extract user roles
def userRoleQuery = """
WITH RoleData AS (
Expand Down
3 changes: 3 additions & 0 deletions frontend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
.git
.DS_Store
5 changes: 3 additions & 2 deletions frontend/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ FROM node:20
WORKDIR /app

# Copy package files and install dependencies
COPY package*.json ./
COPY package.json ./
COPY package-lock.json ./
RUN npm install

# Copy other source files
# Copy other source files - node modules is excluded in .dockerignore
COPY . .

# Expose port 3000 for the app
Expand Down
39 changes: 24 additions & 15 deletions frontend/src/views/ComplianceReports/components/AssessmentCard.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useMemo } from 'react'
import BCButton from '@/components/BCButton'
import BCTypography from '@/components/BCTypography'
import BCWidgetCard from '@/components/BCWidgetCard/BCWidgetCard'
Expand Down Expand Up @@ -52,6 +53,13 @@ export const AssessmentCard = ({
}
})

const filteredChain = useMemo(() => {
return chain.filter((report) => {
const hasHistory = report.history && report.history.length > 0
return hasHistory
})
}, [chain])

return (
<BCWidgetCard
component="div"
Expand Down Expand Up @@ -141,21 +149,22 @@ export const AssessmentCard = ({
</List>
</>
)}
{!!chain.length && (
<>
<BCTypography
sx={{ paddingTop: '16px' }}
component="div"
variant="h6"
color="primary"
>
{t('report:reportHistory')}
</BCTypography>
{chain.map((report) => (
<HistoryCard key={report.version} report={report} />
))}
</>
)}
{filteredChain.length > 0 &&
currentStatus !== COMPLIANCE_REPORT_STATUSES.DRAFT && (
<>
<BCTypography
sx={{ paddingTop: '16px' }}
component="div"
variant="h6"
color="primary"
>
{t('report:reportHistory')}
</BCTypography>
{filteredChain.map((report) => (
<HistoryCard key={report.version} report={report} />
))}
</>
)}

<Role roles={[roles.supplier]}>
{isFeatureEnabled(FEATURE_FLAGS.SUPPLEMENTAL_REPORTING) &&
Expand Down
57 changes: 30 additions & 27 deletions frontend/src/views/ComplianceReports/components/HistoryCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export const HistoryCard = ({ report }) => {
})
.filter((item) => item.status.status !== COMPLIANCE_REPORT_STATUSES.DRAFT)
}, [isGovernmentUser, report.history])

return (
<Accordion>
<AccordionSummary
Expand All @@ -82,33 +83,35 @@ export const HistoryCard = ({ report }) => {
: {report.currentStatus.status}
</BCTypography>
</AccordionSummary>
<AccordionDetails>
<List>
{filteredHistory.map((item, index) => (
<StyledListItem key={index} disablePadding>
<ListItemText
data-test="list-item"
primaryTypographyProps={{ variant: 'body4' }}
>
<span
dangerouslySetInnerHTML={{
__html: t(
`report:complianceReportHistory.${item.status.status}`,
{
createDate: timezoneFormatter({
value: item?.createDate
}),
firstName: item.userProfile.firstName,
lastName: item.userProfile.lastName
}
)
}}
/>
</ListItemText>
</StyledListItem>
))}
</List>
</AccordionDetails>
{filteredHistory.length > 0 && (
<AccordionDetails>
<List>
{filteredHistory.map((item, index) => (
<StyledListItem key={index} disablePadding>
<ListItemText
data-test="list-item"
primaryTypographyProps={{ variant: 'body4' }}
>
<span
dangerouslySetInnerHTML={{
__html: t(
`report:complianceReportHistory.${item.status.status}`,
{
createDate: timezoneFormatter({
value: item?.createDate
}),
firstName: item.userProfile.firstName,
lastName: item.userProfile.lastName
}
)
}}
/>
</ListItemText>
</StyledListItem>
))}
</List>
</AccordionDetails>
)}
</Accordion>
)
}

0 comments on commit 9a05f78

Please sign in to comment.