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

allow cancel/edit a subcourse always when user is an admin #967

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 15 additions & 6 deletions common/courses/states.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { cancelAppointment } from '../appointment/cancel';
import { User, userForStudent } from '../user';
import { addGroupAppointmentsOrganizer } from '../appointment/participants';
import { sendPupilCoursePromotion, sendSubcourseCancelNotifications } from './notifications';
import { isElevated } from '../../graphql/authentication';
import { GraphQLContext } from '../../graphql/context';

const logger = getLogger('Course States');

Expand Down Expand Up @@ -122,7 +124,7 @@ export async function publishSubcourse(subcourse: Subcourse) {

/* ---------------- Subcourse Cancel ------------ */

export async function canCancel(subcourse: Subcourse): Promise<Decision> {
export async function canCancel(subcourse: Subcourse, isAdmin: boolean): Promise<Decision> {
if (!subcourse.published) {
return { allowed: false, reason: 'not-published' };
}
Expand All @@ -131,15 +133,19 @@ export async function canCancel(subcourse: Subcourse): Promise<Decision> {
return { allowed: false, reason: 'already-cancelled' };
}

if (isAdmin) {
return { allowed: true, reason: 'user-is-admin' };
}

if (await subcourseOver(subcourse)) {
return { allowed: false, reason: 'subcourse-ended' };
}

return { allowed: true };
}

export async function cancelSubcourse(user: User, subcourse: Subcourse) {
const can = await canCancel(subcourse);
export async function cancelSubcourse(user: User, subcourse: Subcourse, isAdmin: boolean) {
const can = await canCancel(subcourse, isAdmin);
if (!can.allowed) {
throw new Error(`Cannot cancel Subcourse(${subcourse.id}), reason: ${can.reason}`);
}
Expand All @@ -156,16 +162,19 @@ export async function cancelSubcourse(user: User, subcourse: Subcourse) {

/* --------------- Modify Subcourse ------------------- */

export async function canEditSubcourse(subcourse: Subcourse): Promise<Decision> {
export async function canEditSubcourse(subcourse: Subcourse, isAdmin: boolean): Promise<Decision> {
if (isAdmin) {
return { allowed: true, reason: 'user-is-admin' };
}
if (subcourse.published && (await subcourseOver(subcourse))) {
return { allowed: false, reason: 'course-ended' };
}

return { allowed: true };
}

export async function editSubcourse(subcourse: Subcourse, update: Partial<Subcourse>) {
const can = await canEditSubcourse(subcourse);
export async function editSubcourse(subcourse: Subcourse, update: Partial<Subcourse>, isAdmin: boolean) {
const can = await canEditSubcourse(subcourse, isAdmin);
if (!can.allowed) {
throw new Error(`Cannot edit Subcourse(${subcourse.id}) reason: ${can.reason}`);
}
Expand Down
12 changes: 7 additions & 5 deletions graphql/subcourse/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { canCancel, canEditSubcourse, canPublish } from '../../common/courses/st
import { Arg, Authorized, Ctx, Field, FieldResolver, Int, ObjectType, Query, Resolver, Root } from 'type-graphql';
import { canJoinSubcourse, couldJoinSubcourse, isParticipant } from '../../common/courses/participants';
import { prisma } from '../../common/prisma';
import { getSessionPupil, getSessionStudent, isElevated, isSessionPupil, isSessionStudent } from '../authentication';
import { getSessionPupil, getSessionStudent, isElevated, isSessionPupil, isSessionStudent, isAdmin } from '../authentication';
import { Role } from '../authorizations';
import { PublicCache } from '../cache';
import { LimitedQuery, LimitEstimated } from '../complexity';
Expand Down Expand Up @@ -459,14 +459,16 @@ export class ExtendedFieldsSubcourseResolver {

@FieldResolver((returns) => Decision)
@Authorized(Role.ADMIN, Role.OWNER)
async canCancel(@Root() subcourse: Required<Subcourse>) {
return await canCancel(subcourse);
async canCancel(@Ctx() context: GraphQLContext, @Root() subcourse: Required<Subcourse>) {
const isanAdmin = await isAdmin(context);
return await canCancel(subcourse, isanAdmin);
}

@FieldResolver((returns) => Decision)
@Authorized(Role.ADMIN, Role.OWNER)
async canEdit(@Root() subcourse: Required<Subcourse>) {
return await canEditSubcourse(subcourse);
async canEdit(@Ctx() context: GraphQLContext, @Root() subcourse: Required<Subcourse>) {
const isanAdmin = await isAdmin(context);
return await canEditSubcourse(subcourse, isanAdmin);
}

@FieldResolver((returns) => Decision)
Expand Down
9 changes: 5 additions & 4 deletions graphql/subcourse/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getLogger } from '../../common/logger/logger';
import { prisma } from '../../common/prisma';
import { userForPupil, userForStudent } from '../../common/user';
import { PrerequisiteError } from '../../common/util/error';
import { getSessionPupil, getSessionStudent } from '../authentication';
import { getSessionPupil, getSessionStudent, isAdmin } from '../authentication';
import { AuthorizedDeferred, hasAccess, Role } from '../authorizations';
import { GraphQLContext } from '../context';
import { getFile, removeFile } from '../files';
Expand Down Expand Up @@ -169,20 +169,21 @@ export class MutateSubcourseResolver {
@Arg('subcourse') data: PublicSubcourseEditInput
): Promise<GraphQLModel.Subcourse> {
const subcourse = await getSubcourse(subcourseId, true);
const isanAdmin = await isAdmin(context);
await hasAccess(context, 'Subcourse', subcourse);

logger.info(`Subcourse(${subcourseId}) was edited by User(${context.user.userID})`);
return await editSubcourse(subcourse, data);
return await editSubcourse(subcourse, data, isanAdmin);
}

@Mutation((returns) => Boolean)
@AuthorizedDeferred(Role.ADMIN, Role.OWNER)
async subcourseCancel(@Ctx() context: GraphQLContext, @Arg('subcourseId') subcourseId: number): Promise<boolean> {
const { user } = context;
const subcourse = await getSubcourse(subcourseId);
const isanAdmin = await isAdmin(context);
await hasAccess(context, 'Subcourse', subcourse);

await cancelSubcourse(user, subcourse);
await cancelSubcourse(user, subcourse, isanAdmin);
if (subcourse.conversationId) {
await markConversationAsReadOnly(subcourse.conversationId);
}
Expand Down
Loading