mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
tier plans improving
Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
@@ -10,6 +10,16 @@
|
||||
* → The user's active tier must be at least this rank (exclusive satisfies premium).
|
||||
* group_restriction — { type, group_ids: [number, ...] }
|
||||
* → The user must belong to at least one of these groups.
|
||||
* item_allowlist — { type, item_type: 'course'|'unit'|'lesson', item_ids: [id, ...] }
|
||||
* → Grants access to these EXACT items regardless of level/tier/group — a
|
||||
* curated "preview" override. Checked BEFORE the other rule types below;
|
||||
* a match short-circuits straight to allowed, since it's meant to win
|
||||
* even when a level-lock rule on the same plan would otherwise block it
|
||||
* (e.g. Premium plan mostly locked to 'premium', but 2 specific
|
||||
* Exclusive courses hand-picked as a preview).
|
||||
*
|
||||
* The 3 non-preview rule types combine as AND (any one can deny). item_allowlist
|
||||
* is the one exception — it's an OR-style grant, not another AND constraint.
|
||||
*
|
||||
* Fallback (no access_rules): uses simple tier rank comparison.
|
||||
***********************************************************************************************************************************************************************/
|
||||
@@ -20,19 +30,25 @@
|
||||
const TIER_RANK = { free: 0, premium: 1, exclusive: 2 };
|
||||
|
||||
/**
|
||||
* Evaluates whether a user can access a course.
|
||||
* Evaluates whether a user can access a course (or, via itemMeta, a
|
||||
* standalone unit/lesson — see courses.controller.js's canAccessUnit/
|
||||
* canAccessLesson, which call this the same way canAccessCourse does).
|
||||
*
|
||||
* @param {object} ctx
|
||||
* @param {string} ctx.tier — user's active tier slug
|
||||
* @param {Array} ctx.access_rules — plan_policies.access_rules (may be empty)
|
||||
* @param {number[]} ctx.group_ids — group IDs the user belongs to
|
||||
* @param {object} course
|
||||
* @param {string} course.subscription — course subscription level (slug)
|
||||
* @param {string} course.subscription — course/unit/lesson subscription level (slug)
|
||||
* @param {Object} tierRankMap — { [slug]: rank } loaded from tier_categories; falls back to TIER_RANK
|
||||
* @param {Object} [itemMeta] — { type: 'course'|'unit'|'lesson', id } — identifies the
|
||||
* specific item being checked, so item_allowlist rules can match it. Omit
|
||||
* (or leave id null) to skip item_allowlist matching entirely.
|
||||
* @returns {{ allowed: boolean, reason: string|null }}
|
||||
*/
|
||||
function evaluateCourseAccess(ctx, course, tierRankMap = TIER_RANK) {
|
||||
function evaluateCourseAccess(ctx, course, tierRankMap = TIER_RANK, itemMeta = {}) {
|
||||
const { tier = 'free', access_rules = [], group_ids = [] } = ctx;
|
||||
const { type: itemType = null, id: itemId = null } = itemMeta;
|
||||
const courseSubscription = course.subscription ?? 'free';
|
||||
const userRank = tierRankMap[tier] ?? 0;
|
||||
// Unknown required slug → Infinity so access is always denied (safe default)
|
||||
@@ -41,6 +57,19 @@ function evaluateCourseAccess(ctx, course, tierRankMap = TIER_RANK) {
|
||||
// Rank-0 courses (default/free tier) are always accessible
|
||||
if (courseRank === 0) return { allowed: true, reason: null };
|
||||
|
||||
// item_allowlist short-circuit — a curated preview item wins outright,
|
||||
// bypassing level/tier/group checks below. Checked against every rule on
|
||||
// the plan, not just when access_rules is otherwise empty.
|
||||
if (itemId != null && access_rules && access_rules.length) {
|
||||
for (const rule of access_rules) {
|
||||
if (rule.type === 'item_allowlist' && rule.item_type === itemType) {
|
||||
if ((rule.item_ids ?? []).map(String).includes(String(itemId))) {
|
||||
return { allowed: true, reason: null };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No plan policy — fallback: compare user rank vs course subscription rank
|
||||
if (!access_rules || access_rules.length === 0) {
|
||||
return userRank >= courseRank
|
||||
@@ -49,6 +78,7 @@ function evaluateCourseAccess(ctx, course, tierRankMap = TIER_RANK) {
|
||||
}
|
||||
|
||||
for (const rule of access_rules) {
|
||||
if (rule.type === 'item_allowlist') continue; // handled above
|
||||
if (rule.type === 'course_subscription_access') {
|
||||
if (!(rule.levels ?? []).includes(courseSubscription)) {
|
||||
return { allowed: false, reason: 'subscription_access' };
|
||||
|
||||
Reference in New Issue
Block a user