Skip to content

Commit

Permalink
Add isPageEditor permission (#147)
Browse files Browse the repository at this point in the history
* Add isPageEditor permission

* Format README

* Simplify auth checks

* Update src/services/sessionService.ts

Co-authored-by: Goostaf <[email protected]>

* Update src/services/sessionService.ts

Co-authored-by: Goostaf <[email protected]>

---------

Co-authored-by: Goostaf <[email protected]>
  • Loading branch information
Oscariremma and GAsplund authored Dec 13, 2024
1 parent d248314 commit 081555d
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 43 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ README.md
.git
media
.env*
db
31 changes: 16 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,19 @@ This project uses environment variables to configure its behavior.

The following environment variables are used:

| Variable | Description | Example Value |
| ------------------------- | --------------------------------------------------------------- | ---------------------------------------------------------------------- |
| DATABASE_URL | Database connection URL | `postgresql://postgres:postgres@localhost:5432/postgres?schema=public` |
| GAMMA_API_KEY_ID | Gamma info API key ID | `api-key-id-uuid-here` |
| GAMMA_API_KEY_TOKEN | Gamma info API token | `token` |
| GAMMA_CLIENT_ID | Gamma OAuth client ID | `id` |
| GAMMA_CLIENT_SECRET | Gamma OAuth client secret | `secret` |
| GAMMA_ROOT_URL | Gamma root URL | `https://auth.chalmers.it` |
| BASE_URL | URL that is used as a base for linking to news | `https://chalmers.it` |
| NEXTAUTH_SECRET | Secret used for signing cookies | `secret` |
| NEXTAUTH_URL | URL to the NextAuth API | `http://localhost:3000/api/auth` |
| MEDIA_PATH | Path to store media | `./media` |
| ACTIVE_GROUP_TYPES | Comma-separated list of group types that are considered active | `committee,society` |
| ADMIN_GROUPS | Comma-separated list of groups that are considered admin groups | `styrit` |
| CORPORATE_RELATIONS_GROUP | Group that is considered the corporate relations group | `armit` |
| Variable | Description | Example Value |
| ------------------------- | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| DATABASE_URL | Database connection URL | `postgresql://postgres:postgres@localhost:5432/postgres?schema=public` |
| GAMMA_API_KEY_ID | Gamma info API key ID | `api-key-id-uuid-here` |
| GAMMA_API_KEY_TOKEN | Gamma info API token | `token` |
| GAMMA_CLIENT_ID | Gamma OAuth client ID | `id` |
| GAMMA_CLIENT_SECRET | Gamma OAuth client secret | `secret` |
| GAMMA_ROOT_URL | Gamma root URL | `https://auth.chalmers.it` |
| BASE_URL | URL that is used as a base for linking to news | `https://chalmers.it` |
| NEXTAUTH_SECRET | Secret used for signing cookies | `secret` |
| NEXTAUTH_URL | URL to the NextAuth API | `http://localhost:3000/api/auth` |
| MEDIA_PATH | Path to store media | `./media` |
| ACTIVE_GROUP_TYPES | Comma-separated list of group types that are considered active | `committee,society` |
| ADMIN_GROUPS | Comma-separated list of groups that are considered admin groups | `styrit,digit` |
| PAGE_EDITOR_GROUPS | Comma-separated list of groups that are allowed to edit division pages in addition to admins | `snit,motespresidit` |
| CORPORATE_RELATIONS_GROUP | Group that is considered the corporate relations group | `armit` |
44 changes: 20 additions & 24 deletions src/actions/divisionPages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ import SessionService from '@/services/sessionService';
import MediaService from '@/services/mediaService';
import { MediaType } from '@/services/fileService';

async function checkAuthorization(divisionGroupId?: number | null) {
const isPageEditor = await SessionService.isPageEditor();
const canEditGroup =
divisionGroupId !== undefined && divisionGroupId !== null
? await SessionService.canEditGroupByInternalId(divisionGroupId)
: true;

if (!isPageEditor && !canEditGroup) {
throw new Error('Unauthorized');
}
}

export async function create(
titleEn: string,
titleSv: string,
Expand All @@ -17,14 +29,7 @@ export async function create(
divisionGroupId?: number,
parentId?: number
) {
if (!(await SessionService.isAdmin())) {
if (
divisionGroupId === undefined ||
!(await SessionService.canEditGroupByInternalId(divisionGroupId))
) {
throw new Error('Unauthorized');
}
}
await checkAuthorization(divisionGroupId);

for (const file of files.getAll('file') as unknown as File[]) {
await MediaService.save(file, Object.values(MediaType));
Expand All @@ -50,15 +55,12 @@ export async function create(
export async function deletePage(id: number) {
const divisionGroupId = (await DivisionPageService.getSingleById(id))
?.divisionGroupId;
if (!(await SessionService.isAdmin())) {
if (
divisionGroupId === undefined ||
divisionGroupId === null ||
!(await SessionService.canEditGroupByInternalId(divisionGroupId))
) {
throw new Error('Unauthorized');
}
const isAdmin = await SessionService.isAdmin();

if (!isAdmin) {
await checkAuthorization(divisionGroupId);
}

await DivisionPageService.delete(id);
redirect('/groups');
}
Expand All @@ -79,18 +81,12 @@ export async function edit(
throw new Error('Page not found');
}

await checkAuthorization(page.divisionGroupId);

for (const file of files.getAll('file') as unknown as File[]) {
await MediaService.save(file, Object.values(MediaType));
}

if (!(await SessionService.isAdmin())) {
if (
page.divisionGroupId === null ||
!(await SessionService.canEditGroupByInternalId(page.divisionGroupId))
) {
throw new Error('Unauthorized');
}
}
await DivisionPageService.edit(
id,
titleEn,
Expand Down
7 changes: 5 additions & 2 deletions src/app/[locale]/pages/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,17 @@ export default async function Groups({
}

const Pages = async ({ locale }: { locale: string }) => {
const isAdmin = await SessionService.isAdmin();
const isPageEditor = await SessionService.isPageEditor();
const l = i18nService.getLocale(locale);
const en = locale === 'en';
console.log(isPageEditor);

return (
<ContentPane>
<h2>{l.pages.about}</h2>
{isAdmin && <ActionLink href="/pages/new">{l.pages.create}</ActionLink>}
{isPageEditor && (
<ActionLink href="/pages/new">{l.pages.create}</ActionLink>
)}
<Divider />
<ul className={styles.links}>
<DivisionPages en={en} slug={'/pages'} />
Expand Down
3 changes: 2 additions & 1 deletion src/components/DivisionPage/DivisionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ export default async function DivisionPage(
id?: number,
gammaSuperGroupId?: string
) {
const isPageEditor = await SessionService.isPageEditor();
const isAdmin = await SessionService.isAdmin();
const canEdit =
id && gammaSuperGroupId
? await SessionService.canEditGroup(gammaSuperGroupId).catch(() => false)
: isAdmin;
: isPageEditor;

const isEditing = slug[slug.length - 1] === 'edit';
return isEditing && canEdit
Expand Down
18 changes: 17 additions & 1 deletion src/services/sessionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default class SessionService {
static async isAdmin(s?: Session | null) {
const session = s ?? (await SessionService.getSession());

const adminGroups = (process.env.ADMIN_GROUPS || 'styrit').split(',');
const adminGroups = (process.env.ADMIN_GROUPS ?? 'styrit,digit').split(',');
const groups = SessionService.getActiveGroups();

return session?.user?.id
Expand All @@ -82,6 +82,22 @@ export default class SessionService {
: false;
}

static async isPageEditor(s?: Session | null) {
const session = s ?? (await SessionService.getSession());
if (await this.isAdmin(session)) return true;

const pageEditorGroups = (
process.env.PAGE_EDITOR_GROUPS ?? 'snit,motespresidit'
).split(',');
const groups = SessionService.getActiveGroups();

return session?.user?.id
? (await groups).some((g) =>
pageEditorGroups.includes(g.superGroup!.name)
)
: false;
}

static async isNewsPostOwner(postId: number, s?: Session | null) {
const post = await prisma.newsPost.findUnique({
where: {
Expand Down

0 comments on commit 081555d

Please sign in to comment.