Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"kind": "singleType",
"collectionName": "partner_programs",
"info": {
"singularName": "partner-program",
"pluralName": "partner-programs",
"displayName": "Partner Program",
"description": "Partner portal settings, like the benefits listed per partner level."
},
"options": {
"draftAndPublish": false
},
"pluginOptions": {},
"attributes": {
"benefits": {
"type": "component",
"component": "partner.benefit",
"repeatable": true
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { factories } from "@strapi/strapi";

export default factories.createCoreController(
"api::partner-program.partner-program",
);
5 changes: 5 additions & 0 deletions apps/cms/src/api/partner-program/routes/partner-program.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { factories } from "@strapi/strapi";

export default factories.createCoreRouter(
"api::partner-program.partner-program",
);
5 changes: 5 additions & 0 deletions apps/cms/src/api/partner-program/services/partner-program.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { factories } from "@strapi/strapi";

export default factories.createCoreService(
"api::partner-program.partner-program",
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"kind": "collectionType",
"collectionName": "partner_resources",
"info": {
"singularName": "partner-resource",
"pluralName": "partner-resources",
"displayName": "Partner Resources",
"description": "Gated content for the partner portal's Sales enablement, Tech enablement and Reusable content sections."
},
"options": {
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"title": {
"type": "string",
"required": true
},
"slug": {
"type": "uid",
"targetField": "title",
"required": true
},
"description": {
"type": "text"
},
"section": {
"type": "enumeration",
"required": true,
"enum": ["sales_enablement", "tech_enablement", "reusable_content"]
},
"minimum_level": {
"type": "enumeration",
"required": true,
"default": "Community",
"enum": ["Unlisted", "Community", "Business", "Enterprise"]
},
"category": {
"type": "string"
},
"label": {
"type": "string"
},
"icon": {
"type": "customField",
"customField": "plugin::strapi-lucide-icons.icon"
},
"content": {
"type": "richtext"
},
"file": {
"type": "media",
"multiple": false
},
"link": {
"type": "string"
},
"sort_order": {
"type": "integer",
"default": 0
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { factories } from "@strapi/strapi";

export default factories.createCoreController(
"api::partner-resource.partner-resource",
);
5 changes: 5 additions & 0 deletions apps/cms/src/api/partner-resource/routes/partner-resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { factories } from "@strapi/strapi";

export default factories.createCoreRouter(
"api::partner-resource.partner-resource",
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { factories } from "@strapi/strapi";

export default factories.createCoreService(
"api::partner-resource.partner-resource",
);
23 changes: 23 additions & 0 deletions apps/cms/src/components/partner/benefit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"collectionName": "components_partner_benefits",
"info": {
"displayName": "Benefit",
"description": "A benefit shown to partners of the given level."
},
"options": {},
"attributes": {
"level": {
"type": "enumeration",
"required": true,
"enum": ["Unlisted", "Community", "Business", "Enterprise"]
},
"title": {
"type": "string",
"required": true
},
"description": {
"type": "text"
}
},
"config": {}
}
49 changes: 49 additions & 0 deletions apps/cms/src/extensions/better-auth/controllers/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,55 @@ export default factories.createCoreController(
ctx.body = organizations;
},

/**
* GET /organizations/partners — partner organizations the caller is
* an owner/admin of, i.e. whose partner portal they can open. Scoped
* to the caller like `mine`, so only `is-authenticated` applies.
*/
async partners(ctx) {
const session = ctx.state.betterAuthSession;

const organizations = await getPluginService(
"organization",
).getPartnerPortals({
userId: session.user.id,
});

ctx.body = organizations;
},

/**
* GET /organizations/:id/partner-portal — the partner portal's gated
* content, filtered by the organization's partner level. Gated by
* the `is-authenticated` and `is-organization-owner` policies.
*/
async partnerPortal(ctx) {
const { id } = ctx.params;

const portal = await getPluginService("organization").getPartnerPortal({
organizationId: id,
});
if (!portal) return ctx.notFound();

ctx.body = portal;
},

/**
* GET /organizations/:id/partner-portal/resources/:slug — a single
* partner resource, including its body. Same policies as
* `partnerPortal`.
*/
async partnerResource(ctx) {
const { id, slug } = ctx.params;

const resource = await getPluginService(
"organization",
).getPartnerResource({ organizationId: id, slug });
if (!resource) return ctx.notFound();

ctx.body = resource;
},

async members(ctx) {
const { id } = ctx.params;

Expand Down
42 changes: 42 additions & 0 deletions apps/cms/src/extensions/better-auth/routes/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ export default {
prefix: "",
},
},
{
method: "GET",
path: "/organizations/partners",
handler: "organization.partners",
config: {
// Same as `/organizations/mine` — must stay registered before
// `/organizations/:id`.
auth: false,
policies: ["plugin::better-auth.is-authenticated"],
middlewares: [],
prefix: "",
},
},
{
method: "GET",
path: "/organizations/:id",
Expand All @@ -45,6 +58,35 @@ export default {
handler: "organization.members",
config: { policies: [], middlewares: [], prefix: "" },
},
{
method: "GET",
path: "/organizations/:id/partner-portal",
handler: "organization.partnerPortal",
config: {
// Owners/admins only, same as the web app's own portal gating.
auth: false,
policies: [
"plugin::better-auth.is-authenticated",
"plugin::better-auth.is-organization-owner",
],
middlewares: [],
prefix: "",
},
},
{
method: "GET",
path: "/organizations/:id/partner-portal/resources/:slug",
handler: "organization.partnerResource",
config: {
auth: false,
policies: [
"plugin::better-auth.is-authenticated",
"plugin::better-auth.is-organization-owner",
],
middlewares: [],
prefix: "",
},
},
{
method: "PUT",
path: "/organizations/:id/profile",
Expand Down
Loading
Loading