Skip to content

Commit

Permalink
feat: payments extension (#42)
Browse files Browse the repository at this point in the history
* feat: safe error page

* feat: better error messages

* feat: add payments extension

* clean

* fix: addpayments extension

* fix: install payments

* feat: add relation options to M2M creator

* feat: payments schema

* feat: membership payments fields

* feat: add payment fields to directus_user

* feat: add example data

* feat: add permissions

* feat!: improve dependency logic

* feat: add profile fields

* fix: logout also directus

* fix: editor persmissions

* fix: registration form

* release: v0.1.1
  • Loading branch information
jofmi authored Jan 10, 2024
1 parent 6b261c0 commit dcc4b7b
Show file tree
Hide file tree
Showing 48 changed files with 13,745 additions and 96 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ KEYCLOAK_ADMIN_PASSWORD = 'admin'
KEYCLOAK_DB_PASSWORD = 'changeme'

NUXT_API_TOKEN = "badToken"
NUXT_PUBLIC_DEBUG = "false"
NUXT_PUBLIC_COLLECTIVO_URL = "http://localhost:3000"

NUXT_KEYCLOAK_ADMIN_CLIENT = "admin-cli"
Expand Down
6 changes: 5 additions & 1 deletion collectivo/app/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
export default defineNuxtConfig({
devtools: { enabled: true },
ssr: false,
extends: ["@collectivo/collectivo", "@collectivo/memberships"],
extends: [
"@collectivo/collectivo",
"@collectivo/payments",
"@collectivo/memberships",
],
i18n: {
lazy: true,
langDir: "./lang",
Expand Down
3 changes: 2 additions & 1 deletion collectivo/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
},
"dependencies": {
"@collectivo/collectivo": "workspace:*",
"@collectivo/memberships": "workspace:*"
"@collectivo/memberships": "workspace:*",
"@collectivo/payments": "workspace:*"
},
"devDependencies": {
"@nuxt/devtools": "^1.0.6",
Expand Down
15 changes: 11 additions & 4 deletions collectivo/collectivo/components/collectivo/form/Builder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { FormErrorEvent, FormSubmitEvent } from "#ui/types";
const toast = useToast();
const { t } = useI18n();
const debug = true;
const debug = useRuntimeConfig().public.debug;
const props = defineProps({
fields: Object as PropType<CollectivoFormField[]>,
Expand All @@ -22,6 +22,7 @@ const props = defineProps({
submitLabel: String,
});
console.log("data", props.data);
const form = { fields: props.fields ?? [] };
const loading = ref(false);
Expand Down Expand Up @@ -178,6 +179,7 @@ for (const input of form.fields) {
addInputToSchema(input.key, input, boolean());
}
// Add passed data or default value to field
if (props.data?.[input.key]) {
state[input.key] = props.data[input.key];
} else if ("default" in input && input.default) {
Expand Down Expand Up @@ -423,15 +425,16 @@ async function fillOutAll() {
class="mx-2 my-10 p-6 rounded-lg bg-slate-100 flex flex-col gap-2"
>
<div>
DEBUG Tools. <br />
You are seeing this because NUXT_DEBUG=True
<h3>Debug Tools</h3>
<p>You are seeing this because NUXT_PUBLIC_DEBUG=True</p>
</div>
<div>
<UButton class="btn" @click="fillOutAll">
{{ t("Fill out all") }}
</UButton>
</div>
<div class="text-sm">Form state: {{ state }}</div>
<h4>Form state</h4>
<div class="text-sm">{{ state }}</div>
</div>
</template>

Expand All @@ -448,6 +451,10 @@ async function fillOutAll() {
@apply form-field basis-full;
}
.form-field-half {
@apply form-field basis-full md:basis-1/2;
}
.form-field-xl {
@apply form-field basis-full xl:basis-1/2;
}
Expand Down
2 changes: 1 addition & 1 deletion collectivo/collectivo/components/collectivo/form/Page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { FetchError } from "ofetch";
const toast = useToast();
const { t } = useI18n();
const debug = true;
const debug = useRuntimeConfig().public.debug;
const submitted = ref(false);
const props = defineProps({
Expand Down
4 changes: 3 additions & 1 deletion collectivo/collectivo/composables/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class CollectivoUserStore {

this.data = (await $directus?.request(
readMe({
fields: ["id", "first_name", "last_name", "email"],
// fields: ["id", "first_name", "last_name", "email"],
}),
)) as CollectivoUser;

Expand Down Expand Up @@ -76,6 +76,8 @@ class CollectivoUserStore {

async logout() {
const runtimeConfig = useRuntimeConfig();
const directus = useDirectus();
await directus.logout();

if (runtimeConfig.public.authService === "keycloak") {
const logoutPath = `${runtimeConfig.public.keycloakUrl}/realms/collectivo/protocol/openid-connect/logout`;
Expand Down
1 change: 1 addition & 0 deletions collectivo/collectivo/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default defineNuxtConfig({
keycloakAdminClient: "admin-cli",
keycloakAdminSecret: "**********",
public: {
debug: false,
collectivoUrl: "http://localhost:3000",
authService: "keycloak",
keycloakUrl: "http://keycloak:8080",
Expand Down
2 changes: 1 addition & 1 deletion collectivo/collectivo/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@collectivo/collectivo",
"version": "0.1.0",
"version": "0.1.1",
"description": "Collectivo is a module system for community plattforms.",
"type": "module",
"license": "AGPL-3.0",
Expand Down
1 change: 1 addition & 0 deletions collectivo/collectivo/pages/profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ async function saveProfile(data: CollectivoUser) {
:data="user.data"
:fields="user.fields"
:submit="saveProfile"
submit-label="Save"
/>
</CollectivoContainer>
<CollectivoContainer>
Expand Down
11 changes: 8 additions & 3 deletions collectivo/collectivo/plugins/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,30 @@ export default defineNuxtPlugin(() => {
menu.value.public.push(...publicItems);

const profileInputs: CollectivoFormField[] = [
{
type: "section",
order: 100,
title: "Account details",
},
{
label: "First name",
key: "first_name",
type: "text",
order: 1,
order: 101,
disabled: true,
},
{
label: "Last name",
key: "last_name",
type: "text",
order: 2,
order: 102,
disabled: true,
},
{
label: "Email",
key: "email",
type: "text",
order: 3,
order: 103,
disabled: true,
},
];
Expand Down
2 changes: 1 addition & 1 deletion collectivo/collectivo/server/plugins/registerExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default defineNitroPlugin(() => {
name: "collectivo",
version: pkg.version,
schemas: [
combineSchemas("collectivo", "0.0.1", {}, [
combineSchemas("collectivo", "0.0.1", [
m001_extensions,
m002_settings,
m003_tags,
Expand Down
19 changes: 8 additions & 11 deletions collectivo/collectivo/server/schemas/001_extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,17 +250,14 @@ schema.permissions.push(
permissions: { _and: [{ id: { _eq: "$CURRENT_USER" } }] },
fields: user_fields,
},
{
collection: "directus_users",
roleName: "collectivo_editor",
action: "read",
fields: ["id", ...editor_fields],
},
{
);

for (const action of ["read", "update", "create", "delete"]) {
schema.permissions.push({
collection: "directus_users",
roleName: "collectivo_editor",
action: "update",
action: action,
fields: editor_fields,
permissions: {},
},
);
permissions: { _and: [{ id: { _nnull: true } }] }, // = all users
});
}
2 changes: 0 additions & 2 deletions collectivo/collectivo/server/utils/apiToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ export function verifyCollectivoApiToken(event: any) {
}

if (headers["authorization"] !== useRuntimeConfig().apiToken) {
console.log("headers", headers);
console.log("config", useRuntimeConfig());
throw createError({
statusCode: 401,
statusMessage: "Invalid token",
Expand Down
2 changes: 1 addition & 1 deletion collectivo/collectivo/server/utils/directusQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ export async function createOrUpdateDirectusPermission(
permission.fields = [permission.fields];
}

console.log(permissionDB.fields, permission.fields);
// console.log(permissionDB.fields, permission.fields);

// @ts-ignore
permission.fields = [
Expand Down
1 change: 1 addition & 0 deletions collectivo/collectivo/server/utils/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface ExtensionConfig {
version: string;
description?: string;
schemas?: ExtensionSchema[];

examples?: () => Promise<void>; // Always relates to latest schema
}

Expand Down
65 changes: 45 additions & 20 deletions collectivo/collectivo/server/utils/migrations.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { createItem, readItems, updateItem } from "@directus/sdk";
import ExtensionBaseMigration from "../schemas/001_extensions";
import { ExtensionConfig } from "./extensions";
import { ExtensionSchema } from "./schemas";

// Run pending migrations for a set of extensions, based on db state
export async function migrateAll(
exts: ExtensionConfig[],
createExampleData: boolean = false,
) {
// // TODO Order extensions by dependencies
// console.log(
// "UNSORTED EXTENSIONS",
// exts.map((m) => m.name),
// );
// exts.sort((a, b) => {
// if (!a.schemas) return -1;
// if (!b.schemas) return 1;
// if (a.schemas.at(-1)?.dependencies?.includes(b.name)) return 1;
// if (b.schemas.at(-1)?.dependencies?.includes(a.name)) return -1;
// return 0;
// });
// console.log(
// "SORTED EXTENSIONS",
// exts.map((m) => m.name),
// );

const extsDb = await getExtensionsFromDb();

for (const ext of exts) {
Expand All @@ -21,6 +39,8 @@ export async function migrateAll(
);
}

console.log("CREATE EXAMPLE DATA", createExampleData);

if (createExampleData) {
for (const ext of exts) {
if (ext.examples) {
Expand Down Expand Up @@ -131,6 +151,8 @@ export async function migrateCustom(
}

try {
const extsDb = await getExtensionsFromDb();
// TODO checkSchemaDependencies(schema, extsDb);
await schema.run_before();
await schema.apply();
await schema.run_after();
Expand Down Expand Up @@ -212,15 +234,15 @@ async function runMigrations(ext: ExtensionConfig, extsDb: any[], to?: string) {
);

if (migrationStateIndex < migrationTargetIndex) {
for (const migration of ext.schemas.slice(
for (const schema of ext.schemas.slice(
migrationStateIndex + 1,
migrationTargetIndex + 1,
)) {
try {
// TODO: checkDependencies(migration, extsDb);
await migration.run_before();
await migration.apply();
await migration.run_after();
// TODO checkSchemaDependencies(schema, extsDb);
await schema.run_before();
await schema.apply();
await schema.run_after();
migrationStateIndex++;

await directus.request(
Expand All @@ -231,7 +253,7 @@ async function runMigrations(ext: ExtensionConfig, extsDb: any[], to?: string) {
);
} catch (e) {
logger.error(
`Error applying schema ${ext.schemas[migrationStateIndex].version} of ${ext.name}`,
`Error applying schema ${ext.schemas[migrationStateIndex]?.version} of ${ext.name}`,
);

throw e;
Expand Down Expand Up @@ -262,17 +284,20 @@ async function runMigrations(ext: ExtensionConfig, extsDb: any[], to?: string) {
}

// TODO: Dependency checking
// function checkDependencies(
// migration: CollectivoMigration,
// extsDb: any[]
// ): void {
// if (!migration.dependencies) return;
// for (const dep of migration.dependencies) {
// const depDb = extsDb.find((f) => f.name === dep.extensionName);
// if (!depDb || depDb.migration < dep.migrationId) {
// throw new Error(
// `Dependency not met: ${dep.extensionName} must be at migration ${dep.migrationId}`
// );
// }
// }
// }
function checkSchemaDependencies(schema: ExtensionSchema, extsDb: any[]): void {
console.log("CHECKING DEPENDENCIES", schema.dependencies);
console.log("CURRENT STATE", extsDb);
if (!schema.dependencies) return;

for (const dep of schema.dependencies) {
const depDb = extsDb.find((f) => f.name === dep.extension);

if (!depDb || depDb.schema_version < dep.version) {
throw new Error(
`Dependency not met: ${dep.extension} must be at migration ${dep.version}`,
);
}

console.log("DEPENDENCY MET", dep, dep.version, depDb.schema_version);
}
}
Loading

0 comments on commit dcc4b7b

Please sign in to comment.