Skip to content

Commit

Permalink
Merge pull request #139 from cellajs/development
Browse files Browse the repository at this point in the history
refactor: delete self
  • Loading branch information
flipvh authored Jun 13, 2024
2 parents acb9d95 + 942cc41 commit d17a3cb
Show file tree
Hide file tree
Showing 96 changed files with 14,333 additions and 12,096 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,10 @@ pnpm run dev

### Step 3

The user [seed](/backend/seed/index.ts) is required to add an ADMIN user. Check `/backend/seed` to add more data with [faker.js](https://github.com/faker-js/faker).
The user [seed](/backend/seed/index.ts) is required to add an ADMIN user. Check `/backend/seed` for more info

```bash
pnpm run seed:user
pnpm run seed:organizations
pnpm run seed
```

Use [Drizzle Studio](https://orm.drizzle.team/drizzle-studio/overview) to manage your local db on [local.drizzle.studio](http:local.drizzle.studio)
Expand Down
6 changes: 3 additions & 3 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"start": "tsx dist/index.cjs",
"build": "NODE_ENV=production tsup",
"build:sourcemaps": "NODE_ENV=production tsup && pnpm run sentry:sourcemaps",
"build:dev": "NODE_ENV=development tsup",
"build:dev": "tsup",
"check:types": "tsc",
"dev": "NODE_ENV=development tsup --watch --onSuccess \"tsx dist/index.cjs\"",
"dev": "tsup --watch --onSuccess \"tsx dist/index.cjs\"",
"seed:pivotal": "tsx seed/pivotal.ts",
"seed:user": "tsx seed/user.ts",
"seed:organizations": "tsx seed/organizations.ts",
Expand Down Expand Up @@ -47,7 +47,7 @@
"config": "workspace:*",
"drizzle-orm": "^0.31.0",
"drizzle-zod": "^0.5.1",
"electric-sql": "^0.11.3",
"electric-sql": "^0.12.0",
"email": "workspace:*",
"enforce-unique": "^1.3.0",
"env": "workspace:*",
Expand Down
8 changes: 4 additions & 4 deletions backend/src/db/lucia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import { config } from 'config';
import { Lucia, type SessionCookieOptions, TimeSpan } from 'lucia';

import { env } from 'env';
import { githubSignInCallbackRouteConfig, googleSignInCallbackRouteConfig, microsoftSignInCallbackRouteConfig } from '../modules/auth/routes';
import authRoutesConfig from '../modules/auth/routes';
import { db } from './db';
import { sessionsTable } from './schema/sessions';
import { type UserModel, usersTable } from './schema/users';

export const githubAuth = new GitHub(env.GITHUB_CLIENT_ID || '', env.GITHUB_CLIENT_SECRET || '', {
redirectURI: `${config.backendUrl}/auth${githubSignInCallbackRouteConfig.path}`,
redirectURI: config.backendAuthUrl + authRoutesConfig.githubSignInCallback.path,
});

export const googleAuth = new Google(
env.GOOGLE_CLIENT_ID || '',
env.GOOGLE_CLIENT_SECRET || '',
`${config.backendUrl}/auth${googleSignInCallbackRouteConfig.path}`,
config.backendAuthUrl + authRoutesConfig.googleSignInCallback.path,
);

export const microsoftAuth = new MicrosoftEntraId(
env.MICROSOFT_TENANT_ID || '',
env.MICROSOFT_CLIENT_ID || '',
env.MICROSOFT_CLIENT_SECRET || '',
`${config.backendUrl}/auth${microsoftSignInCallbackRouteConfig.path}`,
config.backendAuthUrl + authRoutesConfig.microsoftSignInCallback.path,
);

// Create Lucia adapter instance
Expand Down
12 changes: 11 additions & 1 deletion backend/src/lib/common-schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ export const entityParamSchema = z.object({
idOrSlug: idSchema.or(slugSchema),
});

export const countsSchema = z.object({
memberships: z.object({
admins: z.number(),
members: z.number(),
total: z.number(),
}),
});

export const imageUrlSchema = z
.string()
.url()
Expand All @@ -91,4 +99,6 @@ export const colorSchema = z
.max(7)
.regex(/^#(?:[0-9a-fA-F]{3}){1,2}$/, 'Color may only contain letters, numbers & starts with #');

export const validUrlSchema = z.string().refine((url: string) => url.startsWith('https'), 'URL must start with https://');
export const validUrlSchema = z
.string()
.refine((url: string) => url.startsWith('https'), 'URL must start with https://');
53 changes: 53 additions & 0 deletions backend/src/lib/counts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { count, eq, sql } from 'drizzle-orm';
import { db } from '../db/db';
import { membershipsTable } from '../db/schema/memberships';
import type { EntityType } from '../types/common';

const getQuery = (entity: EntityType) => {
let columnName: keyof typeof membershipsTable;

switch (entity) {
case 'ORGANIZATION':
columnName = 'organizationId';
break;
case 'PROJECT':
columnName = 'projectId';
break;
default:
throw new Error(`Invalid entity type: ${entity}`);
}

return db
.select({
id: membershipsTable[columnName],
admins: count(sql`CASE WHEN ${membershipsTable.role} = 'ADMIN' THEN 1 ELSE NULL END`).as('admins'),
members: count().as('members'),
})
.from(membershipsTable)
.where(eq(membershipsTable.type, entity))
.groupBy(membershipsTable[columnName])
.as('counts');
};

export function counts<T extends string | undefined = undefined>(
entity: EntityType,
id?: T,
): T extends string
? Promise<{ memberships: { admins: number; members: number; total: number } }>
: Promise<ReturnType<typeof getQuery>>;
export async function counts(entity: EntityType, id?: string | undefined) {
const query = getQuery(entity);

if (id) {
const [{ admins, members }] = await db.select().from(query).where(eq(query.id, id));
return {
memberships: {
admins,
members,
total: members,
},
};
}

return query;
}
16 changes: 10 additions & 6 deletions backend/src/middlewares/guard/is-allowed-to.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ const isAllowedTo =
// Retrieve the context of the entity to be authorized (e.g., 'organization', 'workspace')
const contextEntity = await getEntityContext(ctx, entityType);

console.log('contextEntityLog', contextEntity);

// Check if user or context is missing
if (!contextEntity || !user) {
return errorResponse(ctx, 404, 'not_found', 'warn', entityType, {
Expand Down Expand Up @@ -71,7 +69,7 @@ async function getEntityContext(ctx: any, entityType: ContextEntity) {
return;
}

const idOrSlug = ctx.req.param('idOrSlug');
const idOrSlug = ctx.req.param('idOrSlug') || ctx.req.query(`${entityType.toLowerCase()}Id`);

if (idOrSlug) {
// Handles resolve for direct entity operations (retrieval, update, deletion) based on unique identifier (ID or Slug).
Expand All @@ -95,8 +93,14 @@ async function createEntityContext(entityType: ContextEntity, ctx: any) {
// Return early if entity is not available
if (!entity) return;

// Extract payload from request body
const payload = await ctx.req.json();
// Extract payload from request body, with try/catch to handle potential empty body bug in HONO (see: https://github.com/honojs/hono/issues/2651)
// biome-ignore lint/suspicious/noExplicitAny: Using 'any' here because the payload can be of any type
let payload:Record<string, any> = {};
try {
payload = await ctx.req.json();
} catch {
payload = {};
}

// TODO make this more clear and explicit and tpye safe
// Initialize context to store the custom created context entity based on the lowest possible ancestor
Expand All @@ -111,7 +115,7 @@ async function createEntityContext(entityType: ContextEntity, ctx: any) {
// Continue searching for the lowest ancestor if not found yet
if (!lowestAncestor) {
// Check if ancestor identifier is provided in params or query
let lowestAncestorIdOrSlug = ctx.req.param(ancestor.name)?.toLowerCase() || ctx.req.query(ancestor.name)?.toLowerCase();
let lowestAncestorIdOrSlug = (ctx.req.param(ancestor.name) || ctx.req.param(`${ancestor.name}Id`) || ctx.req.query(ancestor.name) || ctx.req.query(`${ancestor.name}Id`))?.toLowerCase();

// If not found in params or query, check if it's provided in the request body
if (!lowestAncestorIdOrSlug && payload) {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/modules/auth/helpers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const handleCreateUser = async (
return errorResponse(ctx, 409, 'email_exists', 'warn', undefined);
}

const strategy = options?.provider ? options.provider.id : 'EMAIL'
const strategy = options?.provider ? options.provider.id : 'EMAIL';
logEvent('Error creating user', { strategy, errorMessage: (error as Error).message }, 'error');

throw error;
Expand Down
28 changes: 17 additions & 11 deletions backend/src/modules/auth/helpers/verify-email.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { config } from 'config';
import { sendVerificationEmailRouteConfig } from '../routes';
import authRoutesConfig from '../routes';
import { logEvent } from '../../../middlewares/logger/log-event';

export const sendVerificationEmail = (email: string) =>
fetch(config.backendUrl + sendVerificationEmailRouteConfig.path, {
method: sendVerificationEmailRouteConfig.method,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
}),
});
export const sendVerificationEmail = (email: string) => {
try {
fetch(config.backendAuthUrl + authRoutesConfig.sendVerificationEmail.path, {
method: authRoutesConfig.sendVerificationEmail.method,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
}),
});
} catch (err) {
return logEvent('Verification email sending failed');
}
};
Loading

0 comments on commit d17a3cb

Please sign in to comment.