Fixed #194 issues #200
@@ -6,7 +6,7 @@ import pool from '../db';
|
|||||||
import { requireLogin, requireMemberState, requireRole } from '../middleware/auth';
|
import { requireLogin, requireMemberState, requireRole } from '../middleware/auth';
|
||||||
import { getUserActiveLOA } from '../services/db/loaService';
|
import { getUserActiveLOA } from '../services/db/loaService';
|
||||||
import { getAllMembersLite, getMemberSettings, getMembersFull, getMembersLite, getUserData, getUserState, setUserSettings, getFilteredMembers, setUserState, getLastNonSuspendedState } from '../services/db/memberService';
|
import { getAllMembersLite, getMemberSettings, getMembersFull, getMembersLite, getUserData, getUserState, setUserSettings, getFilteredMembers, setUserState, getLastNonSuspendedState } from '../services/db/memberService';
|
||||||
import { getUserRoles } from '../services/db/rolesService';
|
import { getUserRoles, stripUserRoles } from '../services/db/rolesService';
|
||||||
import { memberSettings, MemberState, myData } from '@app/shared/types/member';
|
import { memberSettings, MemberState, myData } from '@app/shared/types/member';
|
||||||
import { Discharge } from '@app/shared/schemas/dischargeSchema';
|
import { Discharge } from '@app/shared/schemas/dischargeSchema';
|
||||||
|
|
||||||
@@ -249,6 +249,7 @@ router.post('/discharge', [requireLogin, requireMemberState(MemberState.Member),
|
|||||||
|
|
||||||
var data: Discharge = req.body;
|
var data: Discharge = req.body;
|
||||||
setUserState(data.userID, MemberState.Discharged, "Member Discharged", author, con, data.reason);
|
setUserState(data.userID, MemberState.Discharged, "Member Discharged", author, con, data.reason);
|
||||||
|
stripUserRoles(data.userID, con);
|
||||||
cancelLatestRank(data.userID, con);
|
cancelLatestRank(data.userID, con);
|
||||||
cancelLatestUnit(data.userID, con);
|
cancelLatestUnit(data.userID, con);
|
||||||
con.commit();
|
con.commit();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import pool from '../../db';
|
|||||||
import { Role, RoleSummary } from '@app/shared/types/roles'
|
import { Role, RoleSummary } from '@app/shared/types/roles'
|
||||||
import { logger } from '../logging/logger';
|
import { logger } from '../logging/logger';
|
||||||
import { memberCache } from '../../routes/auth';
|
import { memberCache } from '../../routes/auth';
|
||||||
|
import * as mariadb from 'mariadb';
|
||||||
|
|
||||||
export async function assignUserGroup(userID: number, roleID: number) {
|
export async function assignUserGroup(userID: number, roleID: number) {
|
||||||
try {
|
try {
|
||||||
@@ -62,4 +63,16 @@ export async function getUsersWithRole(roleId: number): Promise<MemberLight[]> {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return out as MemberLight[]
|
return out as MemberLight[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function stripUserRoles(userID: number, con: mariadb.Pool | mariadb.Connection = pool) {
|
||||||
|
try {
|
||||||
|
const out = await con.query(`DELETE FROM members_roles WHERE member_id = ?;`, [userID]);
|
||||||
|
return { success: true, affectedRows: out.affectedRows };
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('app', 'Failed to strip user roles', error);
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
memberCache.Invalidate(userID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,10 @@ const props = defineProps<{
|
|||||||
member: Member | null
|
member: Member | null
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits(['update:open', 'discharged'])
|
const emit = defineEmits<{
|
||||||
|
'update:open': [value: boolean]
|
||||||
|
'discharged': [value: { data: Discharge }]
|
||||||
|
}>()
|
||||||
|
|
||||||
const formSchema = toTypedSchema(dischargeSchema);
|
const formSchema = toTypedSchema(dischargeSchema);
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
import Spinner from "@/components/ui/spinner/Spinner.vue";
|
import Spinner from "@/components/ui/spinner/Spinner.vue";
|
||||||
import DischargeMember from "@/components/members/DischargeMember.vue";
|
import DischargeMember from "@/components/members/DischargeMember.vue";
|
||||||
import MemberCard from "@/components/members/MemberCard.vue";
|
import MemberCard from "@/components/members/MemberCard.vue";
|
||||||
|
import { useMemberDirectory } from "@/stores/memberDirectory";
|
||||||
|
import { Discharge } from "@shared/schemas/dischargeSchema";
|
||||||
|
|
||||||
// --- State ---
|
// --- State ---
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -149,15 +151,20 @@
|
|||||||
async function onSuspend(member: Member) {
|
async function onSuspend(member: Member) {
|
||||||
await suspendMember(member.member_id);
|
await suspendMember(member.member_id);
|
||||||
await fetchMembers();
|
await fetchMembers();
|
||||||
|
memberCache.invalidateMember(member.member_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onUnsuspend(member: Member) {
|
async function onUnsuspend(member: Member) {
|
||||||
await unsuspendMember(member.member_id);
|
await unsuspendMember(member.member_id);
|
||||||
await fetchMembers();
|
await fetchMembers();
|
||||||
|
memberCache.invalidateMember(member.member_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDischargeSuccess(data) {
|
const memberCache = useMemberDirectory();
|
||||||
|
|
||||||
|
function handleDischargeSuccess(value: { data: Discharge }) {
|
||||||
fetchMembers();
|
fetchMembers();
|
||||||
|
memberCache.invalidateMember(value.data.userID);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -245,7 +252,8 @@
|
|||||||
<TableCell>{{ member.rank }}</TableCell>
|
<TableCell>{{ member.rank }}</TableCell>
|
||||||
<TableCell>{{ member.unit }}</TableCell>
|
<TableCell>{{ member.unit }}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Badge variant="outline" class="capitalize font-normal">{{ MemberState[member.member_state] }}</Badge>
|
<Badge variant="outline" class="capitalize font-normal">{{
|
||||||
|
MemberState[member.member_state] }}</Badge>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Badge v-if="member.loa_until" variant="secondary"
|
<Badge v-if="member.loa_until" variant="secondary"
|
||||||
@@ -262,11 +270,13 @@
|
|||||||
<!-- <DropdownMenuItem @click="navigateToMember(member.member_id)">
|
<!-- <DropdownMenuItem @click="navigateToMember(member.member_id)">
|
||||||
View Profile
|
View Profile
|
||||||
</DropdownMenuItem> -->
|
</DropdownMenuItem> -->
|
||||||
<DropdownMenuItem @click="openDischargeModal(member)"
|
<DropdownMenuItem v-if="member.member_state !== MemberState.Discharged"
|
||||||
|
@click="openDischargeModal(member)"
|
||||||
class="text-destructive focus:bg-destructive focus:text-destructive-foreground font-medium">
|
class="text-destructive focus:bg-destructive focus:text-destructive-foreground font-medium">
|
||||||
Discharge Member
|
Discharge Member
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem v-if="member.member_state !== MemberState.Suspended" @click="onSuspend(member)"
|
<DropdownMenuItem v-if="member.member_state !== MemberState.Suspended"
|
||||||
|
@click="onSuspend(member)"
|
||||||
class="text-destructive focus:bg-destructive focus:text-destructive-foreground font-medium">
|
class="text-destructive focus:bg-destructive focus:text-destructive-foreground font-medium">
|
||||||
Suspend Member
|
Suspend Member
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
|
|||||||
Reference in New Issue
Block a user