@semantq/pylon
Advanced tools
| import pricingPackageService from '../services/pricingPackageService.js'; | ||
| class PricingPackageController { | ||
| async createPricingPackage(req, res) { | ||
| try { | ||
| const result = await pricingPackageService.create(req.body); | ||
| res.status(201).json(result); | ||
| } catch (err) { | ||
| res.status(400).json({ error: err.message }); | ||
| } | ||
| } | ||
| async getPricingPackageById(req, res) { | ||
| try { | ||
| const result = await pricingPackageService.getById(req.params.id); | ||
| res.json(result); | ||
| } catch (err) { | ||
| res.status(404).json({ error: err.message }); | ||
| } | ||
| } | ||
| async getAllPricingPackages(req, res) { | ||
| try { | ||
| const result = await pricingPackageService.getAll(); | ||
| res.json(result); | ||
| } catch (err) { | ||
| res.status(500).json({ error: err.message }); | ||
| } | ||
| } | ||
| async updatePricingPackage(req, res) { | ||
| try { | ||
| // Parse ID from string to integer (for sqlite/mysql; mongo uses string IDs) | ||
| const resourceId = parseInt(req.params.id, 10); | ||
| // Validate parsed ID | ||
| if (isNaN(resourceId)) { | ||
| return res.status(400).json({ error: 'Invalid PricingPackage ID provided. Must be a number.' }); | ||
| } | ||
| const result = await pricingPackageService.update(resourceId, req.body); | ||
| res.json(result); | ||
| } catch (err) { | ||
| res.status(400).json({ error: err.message }); | ||
| } | ||
| } | ||
| async deletePricingPackage(req, res) { | ||
| try { | ||
| // Parse ID from string to integer (for sqlite/mysql; mongo uses string IDs) | ||
| const resourceId = parseInt(req.params.id, 10); | ||
| // Validate parsed ID | ||
| if (isNaN(resourceId)) { | ||
| return res.status(400).json({ error: 'Invalid PricingPackage ID provided. Must be a number.' }); | ||
| } | ||
| await pricingPackageService.delete(resourceId); | ||
| res.status(204).send(); | ||
| } catch (err) { | ||
| if (err.message.includes("Record to delete does not exist")) { | ||
| res.status(404).json({ error: "PricingPackage not found." }); | ||
| } else { | ||
| res.status(400).json({ error: err.message }); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| export default new PricingPackageController(); |
| // Add to your schema.prisma: | ||
| /* | ||
| model Feature { | ||
| id String @id @default(uuid()) | ||
| name String | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| // Add additional fields as needed | ||
| } | ||
| */ | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
| export default class FeatureModel { | ||
| /** | ||
| * Creates a new feature in the database. | ||
| * @param {object} data - The data for the new feature. | ||
| * @returns {Promise<object>} The created feature object. | ||
| */ | ||
| static async create(data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.feature.create({ data }); | ||
| } | ||
| /** | ||
| * Finds a feature by its unique ID. | ||
| * @param {string} id - The ID of the feature to find. | ||
| * @returns {Promise<object|null>} The found feature object, or null if not found. | ||
| */ | ||
| static async findById(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.feature.findUnique({ where: { id } }); | ||
| } | ||
| /// getNonCrudFeatureNames | ||
| static async getNonCrudFeatureNames() { | ||
| const prisma = await getPrismaClient(); | ||
| const result = await prisma.feature.findMany({ | ||
| where: { non_crud_feature_set_name: { not: null } }, // exclude nulls | ||
| select: { id: true, non_crud_feature_set_name: true }, | ||
| }); | ||
| console.log("✅ Prisma returned:", result); | ||
| return result; | ||
| } | ||
| /** | ||
| * Retrieves all features from the database. | ||
| * @returns {Promise<Array<object>>} An array of all feature objects. | ||
| */ | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.feature.findMany(); | ||
| } | ||
| /** | ||
| * Updates an existing feature by its ID. | ||
| * @param {string} id - The ID of the feature to update. | ||
| * @param {object} data - The data to update the feature with. | ||
| * @returns {Promise<object>} The updated feature object. | ||
| */ | ||
| static async update(id, data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.feature.update({ | ||
| where: { id }, | ||
| data, | ||
| }); | ||
| } | ||
| /** | ||
| * Deletes a feature by its ID. | ||
| * @param {string} id - The ID of the feature to delete. | ||
| * @returns {Promise<object>} The deleted feature object. | ||
| */ | ||
| static async delete(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.feature.delete({ where: { id } }); | ||
| } | ||
| /** | ||
| * Finds features with pagination. | ||
| * @param {number} [skip=0] - The number of records to skip. | ||
| * @param {number} [take=10] - The number of records to take. | ||
| * @returns {Promise<Array<object>>} An array of feature objects for the given pagination. | ||
| */ | ||
| static async findWithPagination(skip = 0, take = 10) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.feature.findMany({ | ||
| skip, | ||
| take, | ||
| orderBy: { createdAt: 'desc' }, // Assuming 'createdAt' field exists for ordering | ||
| }); | ||
| } | ||
| } |
| // Add to your schema.prisma: | ||
| /* | ||
| model Metering { | ||
| id String @id @default(uuid()) | ||
| name String | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| // Add additional fields as needed | ||
| } | ||
| */ | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
| export default class MeteringModel { | ||
| static async create(data) { | ||
| console.log("3. inside Metering logUsage"); | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.metering.create({ | ||
| data | ||
| }); | ||
| } | ||
| static async findById(id) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.metering.findUnique({ | ||
| where: { id }, | ||
| include: { | ||
| organization: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async countMonthlyUsage(organizationId, featureName) { | ||
| const prisma = await getPrismaClient(); | ||
| // Ensure organizationId is a string | ||
| const orgId = parseInt(organizationId); | ||
| // Get the start and end of the current month (UTC-safe) | ||
| const now = new Date(); | ||
| const startOfMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1)); | ||
| const endOfMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1)); | ||
| // Count how many records fall within this month | ||
| const count = await prisma.metering.count({ | ||
| where: { | ||
| organizationId: orgId, | ||
| featureName, | ||
| createdAt: { | ||
| gte: startOfMonth, | ||
| lt: endOfMonth, | ||
| }, | ||
| }, | ||
| }); | ||
| return count; | ||
| } | ||
| static async countYearlyUsage(organizationId, featureName) { | ||
| const prisma = await getPrismaClient(); | ||
| // Ensure organizationId is a string | ||
| const orgId = parseInt(organizationId); | ||
| // Get the start and end of the current year (UTC-safe) | ||
| const now = new Date(); | ||
| const startOfYear = new Date(Date.UTC(now.getUTCFullYear(), 0, 1)); // Jan 1 | ||
| const endOfYear = new Date(Date.UTC(now.getUTCFullYear() + 1, 0, 1)); // Jan 1 next year | ||
| // Count how many records fall within this year | ||
| const count = await prisma.metering.count({ | ||
| where: { | ||
| organizationId: orgId, | ||
| featureName, | ||
| createdAt: { | ||
| gte: startOfYear, | ||
| lt: endOfYear, | ||
| }, | ||
| }, | ||
| }); | ||
| return count; | ||
| } | ||
| static async findByOrganizationAndFeature(organizationId, featureId) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.metering.findUnique({ | ||
| where: { | ||
| organizationId_featureId: { | ||
| organizationId, | ||
| featureId | ||
| } | ||
| }, | ||
| include: { | ||
| organization: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.metering.findMany({ | ||
| include: { | ||
| organization: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async update(id, data) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.metering.update({ | ||
| where: { id }, | ||
| data, | ||
| include: { | ||
| organization: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async delete(id) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.metering.delete({ where: { id } }); | ||
| } | ||
| // Pylon-specific methods | ||
| static async getOrCreate(organizationId, featureId) { | ||
| const prisma = await getPrismaClient(); | ||
| const existing = await prisma.metering.findUnique({ | ||
| where: { | ||
| organizationId_featureId: { organizationId, featureId } | ||
| } | ||
| }); | ||
| if (existing) { | ||
| // Check if period needs reset | ||
| if (existing.periodEnd && existing.periodEnd < new Date()) { | ||
| const feature = await prisma.feature.findUnique({ | ||
| where: { id: featureId } | ||
| }); | ||
| const { periodStart, periodEnd } = this.calculatePeriod(feature?.timeframe); | ||
| return prisma.metering.update({ | ||
| where: { id: existing.id }, | ||
| data: { | ||
| currentValue: 0, | ||
| periodStart, | ||
| periodEnd | ||
| } | ||
| }); | ||
| } | ||
| return existing; | ||
| } | ||
| // Create new metering record | ||
| const feature = await prisma.feature.findUnique({ | ||
| where: { id: featureId } | ||
| }); | ||
| const { periodStart, periodEnd } = this.calculatePeriod(feature?.timeframe); | ||
| return prisma.metering.create({ | ||
| data: { | ||
| organizationId, | ||
| featureId, | ||
| currentValue: 0, | ||
| periodStart, | ||
| periodEnd | ||
| } | ||
| }); | ||
| } | ||
| static async incrementUsage(organizationId, featureId, amount = 1) { | ||
| const prisma = await getPrismaClient(); | ||
| const metering = await this.getOrCreate(organizationId, featureId); | ||
| return prisma.metering.update({ | ||
| where: { id: metering.id }, | ||
| data: { currentValue: { increment: amount } } | ||
| }); | ||
| } | ||
| static calculatePeriod(timeframe) { | ||
| const now = new Date(); | ||
| let periodEnd; | ||
| switch (timeframe) { | ||
| case 'MONTHLY': | ||
| periodEnd = new Date(now.getFullYear(), now.getMonth() + 1, 1); | ||
| break; | ||
| case 'YEARLY': | ||
| periodEnd = new Date(now.getFullYear() + 1, 0, 1); | ||
| break; | ||
| default: | ||
| periodEnd = new Date(2100, 0, 1); // Forever | ||
| } | ||
| return { periodStart: now, periodEnd }; | ||
| } | ||
| } |
| // Add to your schema.prisma: | ||
| /* | ||
| model Model { | ||
| id String @id @default(uuid()) | ||
| name String | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| // Add additional fields as needed | ||
| } | ||
| */ | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
| export default class ModelModel { | ||
| /** | ||
| * Creates a new model in the database. | ||
| * @param {object} data - The data for the new model. | ||
| * @returns {Promise<object>} The created model object. | ||
| */ | ||
| static async create(data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.model.create({ data }); | ||
| } | ||
| /** | ||
| * Finds a model by its unique ID. | ||
| * @param {string} id - The ID of the model to find. | ||
| * @returns {Promise<object|null>} The found model object, or null if not found. | ||
| */ | ||
| static async findById(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.model.findUnique({ where: { id } }); | ||
| } | ||
| /** | ||
| * Retrieves all models from the database. | ||
| * @returns {Promise<Array<object>>} An array of all model objects. | ||
| */ | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.model.findMany(); | ||
| } | ||
| /** | ||
| * Updates an existing model by its ID. | ||
| * @param {string} id - The ID of the model to update. | ||
| * @param {object} data - The data to update the model with. | ||
| * @returns {Promise<object>} The updated model object. | ||
| */ | ||
| static async update(id, data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.model.update({ | ||
| where: { id }, | ||
| data, | ||
| }); | ||
| } | ||
| /** | ||
| * Deletes a model by its ID. | ||
| * @param {string} id - The ID of the model to delete. | ||
| * @returns {Promise<object>} The deleted model object. | ||
| */ | ||
| static async delete(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.model.delete({ where: { id } }); | ||
| } | ||
| /** | ||
| * Finds models with pagination. | ||
| * @param {number} [skip=0] - The number of records to skip. | ||
| * @param {number} [take=10] - The number of records to take. | ||
| * @returns {Promise<Array<object>>} An array of model objects for the given pagination. | ||
| */ | ||
| static async findWithPagination(skip = 0, take = 10) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.model.findMany({ | ||
| skip, | ||
| take, | ||
| orderBy: { createdAt: 'desc' }, // Assuming 'createdAt' field exists for ordering | ||
| }); | ||
| } | ||
| } |
| // Add to your schema.prisma: | ||
| /* | ||
| model Organization { | ||
| id String @id @default(uuid()) | ||
| name String | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| // Add additional fields as needed | ||
| } | ||
| */ | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
| export default class OrganizationModel { | ||
| static async create(data) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.organization.create({ data }); | ||
| } | ||
| static async findById(id) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.organization.findUnique({ | ||
| where: { id }, | ||
| include: { | ||
| pricingPackage: { | ||
| include: { | ||
| features: { | ||
| include: { | ||
| feature: true | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }); | ||
| } | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.organization.findMany({ | ||
| include: { | ||
| pricingPackage: true | ||
| } | ||
| }); | ||
| } | ||
| /** | ||
| * Simulates a payment by setting the paid period for a full year. | ||
| * @param {string | number} id - The ID of the organization to update. | ||
| * @returns {Promise<object>} The updated organization record. | ||
| */ | ||
| static async simulatePayment (id) { | ||
| // Get the current time for paidPeriodStart | ||
| const paidPeriodStart = new Date(); | ||
| // Calculate the paidPeriodEnd (one year from now) | ||
| const paidPeriodEnd = new Date(); | ||
| paidPeriodEnd.setFullYear(paidPeriodEnd.getFullYear() + 1); | ||
| const prisma = await getPrismaClient(); | ||
| // Update the organization record | ||
| return prisma.organization.update({ | ||
| where: { id }, | ||
| data: { | ||
| paidPeriodStart: paidPeriodStart, | ||
| paidPeriodEnd: paidPeriodEnd, | ||
| }, | ||
| }); | ||
| } | ||
| static async update(id, data) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.organization.update({ | ||
| where: { id }, | ||
| data, | ||
| }); | ||
| } | ||
| static async delete(id) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.organization.delete({ where: { id } }); | ||
| } | ||
| } |
| // Add to your schema.prisma: | ||
| /* | ||
| model PricingPackage { | ||
| id String @id @default(uuid()) | ||
| name String | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| // Add additional fields as needed | ||
| } | ||
| */ | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
| export default class PricingPackageModel { | ||
| /** | ||
| * Creates a new pricingPackage in the database. | ||
| * @param {object} data - The data for the new pricingPackage. | ||
| * @returns {Promise<object>} The created pricingPackage object. | ||
| */ | ||
| static async create(data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pricingPackage.create({ data }); | ||
| } | ||
| /** | ||
| * Finds a pricingPackage by its unique ID. | ||
| * @param {string} id - The ID of the pricingPackage to find. | ||
| * @returns {Promise<object|null>} The found pricingPackage object, or null if not found. | ||
| */ | ||
| static async findById(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pricingPackage.findUnique({ where: { id } }); | ||
| } | ||
| /** | ||
| * Retrieves all pricingPackages from the database. | ||
| * @returns {Promise<Array<object>>} An array of all pricingPackage objects. | ||
| */ | ||
| /* | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pricingPackage.findMany({include: {features: true } }); | ||
| } */ | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pricingPackage.findMany({ | ||
| // Include all PricingPackage fields by default (no 'select' needed here) | ||
| include: { | ||
| features: { | ||
| include: { | ||
| feature: true, // true includes ALL fields of the Feature model | ||
| }, | ||
| }, | ||
| }, | ||
| }); | ||
| } | ||
| /** | ||
| * Updates an existing pricingPackage by its ID. | ||
| * @param {string} id - The ID of the pricingPackage to update. | ||
| * @param {object} data - The data to update the pricingPackage with. | ||
| * @returns {Promise<object>} The updated pricingPackage object. | ||
| */ | ||
| static async update(id, data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pricingPackage.update({ | ||
| where: { id }, | ||
| data, | ||
| }); | ||
| } | ||
| /** | ||
| * Deletes a pricingPackage by its ID. | ||
| * @param {string} id - The ID of the pricingPackage to delete. | ||
| * @returns {Promise<object>} The deleted pricingPackage object. | ||
| */ | ||
| static async delete(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pricingPackage.delete({ where: { id } }); | ||
| } | ||
| /** | ||
| * Finds pricingPackages with pagination. | ||
| * @param {number} [skip=0] - The number of records to skip. | ||
| * @param {number} [take=10] - The number of records to take. | ||
| * @returns {Promise<Array<object>>} An array of pricingPackage objects for the given pagination. | ||
| */ | ||
| static async findWithPagination(skip = 0, take = 10) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pricingPackage.findMany({ | ||
| skip, | ||
| take, | ||
| orderBy: { createdAt: 'desc' }, // Assuming 'createdAt' field exists for ordering | ||
| }); | ||
| } | ||
| } |
| // Add to your schema.prisma: | ||
| /* | ||
| model PricingPackageFeature { | ||
| id String @id @default(uuid()) | ||
| name String | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| // Add additional fields as needed | ||
| } | ||
| */ | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
| export default class PricingPackageFeatureModel { | ||
| static async create(data) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.pricingPackageFeature.create({ | ||
| data, | ||
| include: { | ||
| pricingPackage: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async findById(id) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.pricingPackageFeature.findUnique({ | ||
| where: { id }, | ||
| include: { | ||
| pricingPackage: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async findByPackageAndFeature(pricingPackageId, featureId) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.pricingPackageFeature.findUnique({ | ||
| where: { | ||
| pricingPackageId_featureId: { | ||
| pricingPackageId, | ||
| featureId | ||
| } | ||
| }, | ||
| include: { | ||
| pricingPackage: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.pricingPackageFeature.findMany({ | ||
| include: { | ||
| pricingPackage: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async update(id, data) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.pricingPackageFeature.update({ | ||
| where: { id }, | ||
| data, | ||
| include: { | ||
| pricingPackage: true, | ||
| feature: true | ||
| } | ||
| }); | ||
| } | ||
| static async delete(id) { | ||
| const prisma = await getPrismaClient(); | ||
| return prisma.pricingPackageFeature.delete({ | ||
| where: { id } | ||
| }); | ||
| } | ||
| } |
| // Add to your schema.prisma: | ||
| /* | ||
| model Pylon { | ||
| id String @id @default(uuid()) | ||
| name String | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| // Add additional fields as needed | ||
| } | ||
| */ | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
| export default class PylonModel { | ||
| /** | ||
| * Creates a new pylon in the database. | ||
| * @param {object} data - The data for the new pylon. | ||
| * @returns {Promise<object>} The created pylon object. | ||
| */ | ||
| static async create(data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.create({ data }); | ||
| } | ||
| /** | ||
| * Finds a pylon by its unique ID. | ||
| * @param {string} id - The ID of the pylon to find. | ||
| * @returns {Promise<object|null>} The found pylon object, or null if not found. | ||
| */ | ||
| static async findById(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.findUnique({ where: { id } }); | ||
| } | ||
| /** | ||
| * Retrieves all pylons from the database. | ||
| * @returns {Promise<Array<object>>} An array of all pylon objects. | ||
| */ | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.findMany(); | ||
| } | ||
| /** | ||
| * Updates an existing pylon by its ID. | ||
| * @param {string} id - The ID of the pylon to update. | ||
| * @param {object} data - The data to update the pylon with. | ||
| * @returns {Promise<object>} The updated pylon object. | ||
| */ | ||
| static async update(id, data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.update({ | ||
| where: { id }, | ||
| data, | ||
| }); | ||
| } | ||
| /** | ||
| * Deletes a pylon by its ID. | ||
| * @param {string} id - The ID of the pylon to delete. | ||
| * @returns {Promise<object>} The deleted pylon object. | ||
| */ | ||
| static async delete(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.delete({ where: { id } }); | ||
| } | ||
| /** | ||
| * Finds pylons with pagination. | ||
| * @param {number} [skip=0] - The number of records to skip. | ||
| * @param {number} [take=10] - The number of records to take. | ||
| * @returns {Promise<Array<object>>} An array of pylon objects for the given pagination. | ||
| */ | ||
| static async findWithPagination(skip = 0, take = 10) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.findMany({ | ||
| skip, | ||
| take, | ||
| orderBy: { createdAt: 'desc' }, // Assuming 'createdAt' field exists for ordering | ||
| }); | ||
| } | ||
| } |
| import express from 'express'; | ||
| import pricingPackageController from '../controllers/pricingPackageController.js'; | ||
| // Import authentication and authorization middleware | ||
| import { validateApiKey } from '../../../../middleware/validateApiKey.js'; | ||
| import { authenticateToken } from '@semantq/auth/lib/middleware/authMiddleware.js'; | ||
| import { authorize } from '@semantq/auth/lib/middleware/authorize.js'; | ||
| const router = express.Router(); | ||
| // ========================================================================= | ||
| // 🔵 API_KEY - Service-to-service communication - DIRECT MIDDLEWARE | ||
| // THIS MUST COME FIRST to ensure it is not blocked by /pricingPackages/:id | ||
| // For example: | ||
| // router.get('/pricingPackages/stats', validateApiKey, pricingPackageController.getPricingPackageStats); | ||
| // ========================================================================= | ||
| // 🟢 PUBLIC - No authentication | ||
| // For example: | ||
| // router.get('/pricingPackages/public/:id', pricingPackageController.getPublicPricingPackageById); | ||
| // router.get('/pricingPackages/latest', pricingPackageController.getLatestPricingPackages); | ||
| // 🟡 AUTHENTICATED - Logged-in users only | ||
| router.get('/pricingPackage/pricingPackages', pricingPackageController.getAllPricingPackages); | ||
| router.get('/pricingPackage/pricingPackages/:id', authenticateToken, pricingPackageController.getPricingPackageById); | ||
| router.post('/pricingPackage/pricingPackages', authenticateToken, pricingPackageController.createPricingPackage); | ||
| router.put('/pricingPackage/pricingPackages/:id', authenticateToken, pricingPackageController.updatePricingPackage); | ||
| router.delete('/pricingPackage/pricingPackages/:id', authenticateToken, pricingPackageController.deletePricingPackage); // 🆕 DELETE route added | ||
| // 🟠 AUTHORIZED - Specific user roles | ||
| // For example, this route requires an access level of 2 | ||
| // router.patch('/pricingPackages/:id', authenticateToken, authorize(2), pricingPackageController.patchPricingPackage); | ||
| // router.delete('/pricingPackages/:id/admin', authenticateToken, authorize(3), pricingPackageController.adminDeletePricingPackage); | ||
| // 🔴 FULLY_PROTECTED - API key + user authentication | ||
| // For example: | ||
| // router.post('/pricingPackages/bulk', validateApiKey, authenticateToken, pricingPackageController.bulkCreatePricingPackages); | ||
| // 🚨 FULLY_AUTHORIZED - API key + user authentication + specific role | ||
| // For example: | ||
| // router.post('/pricingPackages/system', validateApiKey, authenticateToken, authorize(3), pricingPackageController.systemCreatePricingPackage); | ||
| export default router; |
| import PricingPackageModel from '../models/mysql/PricingPackage.js'; | ||
| class PricingPackageService { | ||
| async create(data) { | ||
| const { | ||
| name, | ||
| priceMonthly, | ||
| priceYearly, | ||
| isStandard, | ||
| pricingTableLabel, | ||
| yearlyPriceDiscountPercentage | ||
| } = data; | ||
| const finalData = { | ||
| name: name, | ||
| priceMonthly: priceMonthly ? parseInt(priceMonthly) : null, | ||
| priceYearly: priceYearly ? parseInt(priceYearly) : null, | ||
| isStandard: isStandard === '1' || isStandard === 1 || isStandard === true, | ||
| pricingTableLabel: pricingTableLabel || null, | ||
| yearlyPriceDiscountPercentage: yearlyPriceDiscountPercentage | ||
| ? parseFloat(yearlyPriceDiscountPercentage) | ||
| : null | ||
| }; | ||
| return await PricingPackageModel.create(finalData); | ||
| } | ||
| async getById(id) { | ||
| return await PricingPackageModel.findById(id); | ||
| } | ||
| async getAll() { | ||
| return await PricingPackageModel.findAll(); | ||
| } | ||
| async update(id, data) { | ||
| return await PricingPackageModel.update(id, data); | ||
| } | ||
| async delete(id) { | ||
| return await PricingPackageModel.delete(id); | ||
| } | ||
| } | ||
| export default new PricingPackageService(); |
| import PylonModel from '../models/mysql/Pylon.js'; | ||
| import UserModel from '../../../../models/mysql/User.js'; | ||
| import MeteringModel from '../models/mysql/Metering.js'; | ||
| class PylonService { | ||
| constructor() { | ||
| // You can initialize properties here if needed | ||
| } | ||
| // FIXED: Proper middleware factory function | ||
| featureGuard(model, action) { | ||
| return async (req, res, next) => { | ||
| try { | ||
| //console.log("THERE?",req.userId); | ||
| let isAllowed = false; | ||
| //let hasCredit = false; | ||
| let notAlloweMessage; | ||
| let noCreditMessage; | ||
| const routeFeature = `${model.toLowerCase()}_${action}`; // e.g., Form + create → form_create | ||
| // Retrieve user data | ||
| const userData = await UserModel.getPylonUserById(req.userId); | ||
| //console.log('- userData:', JSON.stringify(userData,null,2)); | ||
| const features = Object.fromEntries( | ||
| userData.organization.pricingPackage.features.map(f => [ | ||
| f.feature.name, | ||
| { | ||
| limitValue: f.limitValue, | ||
| status: f.status, | ||
| count: f.feature.count, | ||
| timeframe: f.feature.timeframe | ||
| } | ||
| ]) | ||
| ); | ||
| //console.log("Feature Map:", features); | ||
| if (!userData) { | ||
| console.log('User not found:', req.userId); | ||
| return res.status(404).json({ message: 'User not found' }); | ||
| } | ||
| // Extract user settings | ||
| const userSettings = userData.userSettings; | ||
| // console.log('- User Settings:', userSettings); | ||
| //console.log('- routeFeature:', routeFeature); | ||
| if(userSettings.includes(routeFeature)) { | ||
| isAllowed = true; | ||
| // console.log("routeFeature",isAllowed); | ||
| } else { | ||
| notAlloweMessage = 'You have no access to this feature'; | ||
| } | ||
| // Check feature access or quota | ||
| const hasCredit = await this.checkCredit(userData, routeFeature, features); | ||
| //console.log("hasCredit",hasCredit); | ||
| if(!hasCredit.status) { | ||
| noCreditMessage = `${features[routeFeature]?.timeframe} Quota exceeded. You need to upgrade your plan.`; | ||
| } | ||
| if(isAllowed && hasCredit.status) { | ||
| //console.log('Feature access granted'); | ||
| // prepare data need to metering | ||
| // metering happens at controller level after succesful record creation | ||
| req.userData = { | ||
| id: userData.id, | ||
| organizationId: userData.organization?.id, | ||
| featureName: routeFeature, | ||
| action: action, | ||
| }; | ||
| req.pylon = true; // so that in your controller | ||
| next(); | ||
| } else { | ||
| console.log(`${features[routeFeature]?.timeframe} Quota exceeded for user:`, req.userId); | ||
| return res.status(403).json({ | ||
| message: `${notAlloweMessage || ''} ${noCreditMessage}`.trim(), | ||
| }); | ||
| } | ||
| } catch (error) { | ||
| console.error('Error in featureGuard:', error); | ||
| return res.status(500).json({ | ||
| message: 'Internal server error in feature guard' | ||
| }); | ||
| } | ||
| }; | ||
| } | ||
| // Helper method for feature access logic | ||
| async checkCredit(userData, routeFeature, features) { | ||
| const timeframe = features[routeFeature]?.timeframe; | ||
| const limitValue = features[routeFeature]?.limitValue; | ||
| const status = features[routeFeature]?.status; | ||
| const count = features[routeFeature]?.count; | ||
| /// STATUS IS false we return false regardless of count metering or not | ||
| if (!status) { | ||
| return { | ||
| status: false, | ||
| message: 'This feature is disabled' | ||
| }; | ||
| } | ||
| // if this is a count based feature | ||
| if (count) { | ||
| const usageCount = timeframe === "MONTHLY" | ||
| ? await MeteringModel.countMonthlyUsage(userData.organizationId, routeFeature) | ||
| : await MeteringModel.countYearlyUsage(userData.organizationId, routeFeature); | ||
| const credit = limitValue - usageCount; | ||
| if (credit <= 0) { | ||
| return { | ||
| status: false, | ||
| message: `Quota exhausted for this ${timeframe.toLowerCase()}` | ||
| }; | ||
| } else { | ||
| // return true if credit is still available | ||
| return { | ||
| status: true, | ||
| remaining: credit | ||
| }; | ||
| } | ||
| } | ||
| // For features that are not count-based | ||
| return { | ||
| status: true | ||
| }; | ||
| } | ||
| async logUsage(data) { | ||
| const usageData = { | ||
| organizationId: parseInt(data.organizationId,10), | ||
| featureName: data.featureName, | ||
| action: data.action, | ||
| metadata: { userId: data.id } | ||
| }; | ||
| return await MeteringModel.create(usageData); | ||
| } | ||
| async create(data) { | ||
| return await PylonModel.create(data); | ||
| } | ||
| async getById(id) { | ||
| return await PylonModel.findById(id); | ||
| } | ||
| async getAll() { | ||
| return await PylonModel.findAll(); | ||
| } | ||
| async update(id, data) { | ||
| return await PylonModel.update(id, data); | ||
| } | ||
| async delete(id) { | ||
| return await PylonModel.delete(id); | ||
| } | ||
| } | ||
| export default new PylonService(); |
| import featureService from '../services/featureService.js'; | ||
| class FeatureController { | ||
| // featureController.js | ||
| async createFeature(req, res) { | ||
| try { | ||
| const result = await featureService.create(req.body); | ||
| const payloadData = req.body?.data ?? req.body ?? {}; | ||
| const { | ||
| name, | ||
| unit, | ||
| model_action, | ||
| description, | ||
| meterType, | ||
| timeframe, | ||
| feature_type, | ||
| feature_set_name_options, | ||
| feature_set_name, | ||
| non_crud_name, | ||
| } = payloadData; | ||
| // 1. Validation Check for required feature_type | ||
| if (!feature_type || (feature_type !== 'Crud' && feature_type !== 'non_crud')) { | ||
| throw new Error("Feature type is required and must be 'Crud' or 'non_crud'."); | ||
| } | ||
| let finalName; | ||
| let finalFeatureSet = null; // Default to null for non_crud_feature_set_name | ||
| const isCrud = feature_type === 'Crud'; | ||
| // 2. Conditional Logic for Naming and Feature Set | ||
| if (isCrud) { | ||
| // --- CRUD Feature Logic (Guaranteed to be set) --- | ||
| if (!name || !model_action) { | ||
| throw new Error("Missing Model Name or Action for a CRUD feature."); | ||
| } | ||
| // Set the final required 'name' argument for Prisma | ||
| finalName = `${name}_${model_action}`; | ||
| // finalFeatureSet remains null, which is correct for CRUD. | ||
| } else { | ||
| // --- NON-CRUD Feature Logic --- | ||
| if (!non_crud_name) { | ||
| throw new Error("Missing Non-CRUD Feature Name."); | ||
| } | ||
| // Set the final required 'name' argument for Prisma | ||
| finalName = non_crud_name; | ||
| // Set the non_crud_feature_set_name | ||
| if (feature_set_name_options === 'add_new') { | ||
| finalFeatureSet = feature_set_name; | ||
| } else { | ||
| finalFeatureSet = feature_set_name_options; | ||
| } | ||
| } | ||
| // 3. Transform Metering Fields to Booleans | ||
| const supportsCount = meterType?.includes("COUNT") ?? null; | ||
| const supportsOnOff = meterType?.includes("ON_OFF") ?? null; | ||
| // 4. BUILD FINAL DATA: finalName MUST be present here. | ||
| const finalData = { | ||
| // --- CRITICAL FIX: finalName must be defined and passed --- | ||
| name: finalName, // This is now guaranteed to be set | ||
| // Standard Fields | ||
| unit: unit, | ||
| description: description, | ||
| timeframe: timeframe, | ||
| // Metering Fields | ||
| count: supportsCount, | ||
| on_off: supportsOnOff, | ||
| // Non-CRUD Specific Fields (Set for non-CRUD, null for CRUD) | ||
| non_crud: !isCrud ? 1 : null, | ||
| non_crud_feature_set_name: finalFeatureSet, // Null for CRUD, set for Non-CRUD | ||
| }; | ||
| // 5. Call the service | ||
| const result = await featureService.create(finalData); | ||
| res.status(201).json(result); | ||
| } catch (err) { | ||
| res.status(400).json({ error: err.message }); | ||
| console.error("Error creating feature:", err); | ||
| // Check if the error is the Prisma validation error | ||
| if (err.name === 'PrismaClientValidationError') { | ||
| res.status(400).json({ | ||
| error: "Database validation failed. Required field is missing.", | ||
| detail: err.message | ||
| }); | ||
| } else { | ||
| res.status(400).json({ | ||
| error: "Failed to process feature creation request.", | ||
| detail: err.message | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| } // ← THIS CLOSING BRACE WAS MISSING | ||
| async getFeatureById(req, res) { | ||
| async getNonCrudFeatureNames(req, res) { | ||
| try { | ||
| const result = await featureService.getById(req.params.id); | ||
| const result = await featureService.getNonCrudFeatureNames(); | ||
| res.json(result); | ||
@@ -22,5 +113,5 @@ } catch (err) { | ||
| async getFeatureByName(req, res) { | ||
| async getFeatureById(req, res) { | ||
| try { | ||
| const result = await featureService.getByName(req.params.name); | ||
| const result = await featureService.getById(req.params.id); | ||
| res.json(result); | ||
@@ -43,3 +134,11 @@ } catch (err) { | ||
| try { | ||
| const result = await featureService.update(req.params.id, req.body); | ||
| // Parse ID from string to integer (for sqlite/mysql; mongo uses string IDs) | ||
| const resourceId = parseInt(req.params.id, 10); | ||
| // Validate parsed ID | ||
| if (isNaN(resourceId)) { | ||
| return res.status(400).json({ error: 'Invalid Feature ID provided. Must be a number.' }); | ||
| } | ||
| const result = await featureService.update(resourceId, req.body); | ||
| res.json(result); | ||
@@ -53,6 +152,18 @@ } catch (err) { | ||
| try { | ||
| await featureService.delete(req.params.id); | ||
| // Parse ID from string to integer (for sqlite/mysql; mongo uses string IDs) | ||
| const resourceId = parseInt(req.params.id, 10); | ||
| // Validate parsed ID | ||
| if (isNaN(resourceId)) { | ||
| return res.status(400).json({ error: 'Invalid Feature ID provided. Must be a number.' }); | ||
| } | ||
| await featureService.delete(resourceId); | ||
| res.status(204).send(); | ||
| } catch (err) { | ||
| res.status(400).json({ error: err.message }); | ||
| if (err.message.includes("Record to delete does not exist")) { | ||
| res.status(404).json({ error: "Feature not found." }); | ||
| } else { | ||
| res.status(400).json({ error: err.message }); | ||
| } | ||
| } | ||
@@ -59,0 +170,0 @@ } |
@@ -13,2 +13,5 @@ import meteringService from '../services/meteringService.js'; | ||
| async getMeteringById(req, res) { | ||
@@ -15,0 +18,0 @@ try { |
@@ -6,2 +6,3 @@ import organizationService from '../services/organizationService.js'; | ||
| try { | ||
| console.log(req.body); | ||
| const result = await organizationService.create(req.body); | ||
@@ -8,0 +9,0 @@ res.status(201).json(result); |
@@ -6,3 +6,18 @@ import pricingPackageFeatureService from '../services/pricingPackageFeatureService.js'; | ||
| try { | ||
| const result = await pricingPackageFeatureService.create(req.body); | ||
| const { seats,pricingPackageId, featureId, limitValue, status } = req.body; | ||
| const finalData = { | ||
| pricingPackageId:pricingPackageId, | ||
| featureId: featureId, | ||
| limitValue: parseInt(limitValue,10), | ||
| status: parseInt(status) > 0 ? true : false | ||
| } | ||
| if (seats) { | ||
| finalData.seats = parseInt(seats,10); | ||
| } | ||
| const result = await pricingPackageFeatureService.create(finalData); | ||
| res.status(201).json(result); | ||
@@ -9,0 +24,0 @@ } catch (err) { |
@@ -14,3 +14,3 @@ // Add to your schema.prisma: | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../lib/prisma.js'; | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
@@ -17,0 +17,0 @@ export default class FeatureModel { |
@@ -14,3 +14,3 @@ // Add to your schema.prisma: | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../lib/prisma.js'; | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
@@ -17,0 +17,0 @@ export default class MeteringModel { |
@@ -14,3 +14,3 @@ // Add to your schema.prisma: | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../lib/prisma.js'; | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
@@ -17,0 +17,0 @@ export default class ModelModel { |
@@ -14,3 +14,3 @@ // Add to your schema.prisma: | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../lib/prisma.js'; | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
@@ -17,0 +17,0 @@ |
@@ -14,3 +14,3 @@ // Add to your schema.prisma: | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../lib/prisma.js'; | ||
| import getPrismaClient from '../../../../../lib/prisma.js'; | ||
@@ -17,0 +17,0 @@ export default class PricingPackageFeatureModel { |
+1
-1
| { | ||
| "name": "@semantq/pylon", | ||
| "version": "1.0.1", | ||
| "version": "1.0.2", | ||
| "description": "Feature Guard Package For SaaS Applications", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
| import express from 'express'; | ||
| import pricingPackageFeatureController from '../controllers/pricingPackageFeatureController.js'; | ||
| import featureController from '../controllers/featureController.js'; | ||
| // Import authentication and authorization middleware | ||
| import { validateApiKey } from '../../../../middleware/validateApiKey.js'; | ||
| import { authenticateToken } from '@semantq/auth/lib/middleware/authMiddleware.js'; | ||
@@ -8,9 +10,43 @@ import { authorize } from '@semantq/auth/lib/middleware/authorize.js'; | ||
| // 🟢 ADMIN ONLY - Pricing package feature management | ||
| router.post('/pricing-package-features', authenticateToken, authorize(3), pricingPackageFeatureController.createPricingPackageFeature); | ||
| router.get('/pricing-package-features', authenticateToken, pricingPackageFeatureController.getAllPricingPackageFeatures); | ||
| router.get('/pricing-package-features/:id', authenticateToken, pricingPackageFeatureController.getPricingPackageFeatureById); | ||
| router.put('/pricing-package-features/:id', authenticateToken, authorize(3), pricingPackageFeatureController.updatePricingPackageFeature); | ||
| router.delete('/pricing-package-features/:id', authenticateToken, authorize(3), pricingPackageFeatureController.deletePricingPackageFeature); | ||
| const model = 'Feature'; | ||
| // ========================================================================= | ||
| // 🔵 API_KEY - Service-to-service communication - DIRECT MIDDLEWARE | ||
| // THIS MUST COME FIRST to ensure it is not blocked by /features/:id | ||
| // For example: | ||
| // router.get('/features/stats', validateApiKey, featureController.getFeatureStats); | ||
| // ========================================================================= | ||
| // 🟢 PUBLIC - No authentication | ||
| // For example: | ||
| // router.get('/features/public/:id', featureController.getPublicFeatureById); | ||
| // router.get('/features/latest', featureController.getLatestFeatures); | ||
| // 🟡 AUTHENTICATED - Logged-in users only | ||
| // /@semantq/pylon/feature/features/noncrud | ||
| router.get('/feature/features', authenticateToken, featureController.getAllFeatures); | ||
| router.get('/feature/features/:id', authenticateToken, featureController.getFeatureById); | ||
| // get non crud feature set names | ||
| router.get('/feature/features/noncrud/names', authenticateToken, featureController.getNonCrudFeatureNames); | ||
| router.post('/feature/features', authenticateToken, featureController.createFeature); | ||
| router.put('/feature/features/:id', authenticateToken, featureController.updateFeature); | ||
| router.delete('/feature/features/:id', authenticateToken, featureController.deleteFeature); // 🆕 DELETE route added | ||
| // 🟠 AUTHORIZED - Specific user roles | ||
| // For example, this route requires an access level of 2 | ||
| // router.patch('/features/:id', authenticateToken, authorize(2), featureController.patchFeature); | ||
| // router.delete('/features/:id/admin', authenticateToken, authorize(3), featureController.adminDeleteFeature); | ||
| // 🔴 FULLY_PROTECTED - API key + user authentication | ||
| // For example: | ||
| // router.post('/features/bulk', validateApiKey, authenticateToken, featureController.bulkCreateFeatures); | ||
| // 🚨 FULLY_AUTHORIZED - API key + user authentication + specific role | ||
| // For example: | ||
| // router.post('/features/system', validateApiKey, authenticateToken, authorize(3), featureController.systemCreateFeature); | ||
| export default router; |
| import express from 'express'; | ||
| import meteringController from '../controllers/meteringController.js'; | ||
| // Import authentication and authorization middleware | ||
| import { validateApiKey } from '../middleware/validateApiKey.js'; | ||
| import { validateApiKey } from '../../../../middleware/validateApiKey.js'; | ||
| import { authenticateToken } from '@semantq/auth/lib/middleware/authMiddleware.js'; | ||
@@ -24,2 +24,6 @@ import { authorize } from '@semantq/auth/lib/middleware/authorize.js'; | ||
| router.get('/meterings', authenticateToken, meteringController.getAllMeterings); | ||
| // | ||
| //router.get('/meterings/monthly/usage/:organizationId/:featureName', authenticateToken, meteringController.getMonthlyUsage); | ||
| router.get('/meterings/:id', authenticateToken, meteringController.getMeteringById); | ||
@@ -26,0 +30,0 @@ router.post('/meterings', authenticateToken, meteringController.createMetering); |
| import express from 'express'; | ||
| import modelController from '../controllers/modelController.js'; | ||
| // Import authentication and authorization middleware | ||
| import { validateApiKey } from '../middleware/validateApiKey.js'; | ||
| import { validateApiKey } from '../../../../middleware/validateApiKey.js'; | ||
| import { authenticateToken } from '@semantq/auth/lib/middleware/authMiddleware.js'; | ||
@@ -23,7 +23,7 @@ import { authorize } from '@semantq/auth/lib/middleware/authorize.js'; | ||
| // 🟡 AUTHENTICATED - Logged-in users only | ||
| router.get('/models', modelController.getAllModels); | ||
| router.get('/models/:id', authenticateToken, modelController.getModelById); | ||
| router.post('/models', authenticateToken, modelController.createModel); | ||
| router.put('/models/:id', authenticateToken, modelController.updateModel); | ||
| router.delete('/models/:id', authenticateToken, modelController.deleteModel); // 🆕 DELETE route added | ||
| router.get('/model/models', modelController.getAllModels); | ||
| router.get('/model/models/:id', authenticateToken, modelController.getModelById); | ||
| router.post('/model/models', authenticateToken, modelController.createModel); | ||
| router.put('/model/models/:id', authenticateToken, modelController.updateModel); | ||
| router.delete('/model/models/:id', authenticateToken, modelController.deleteModel); // 🆕 DELETE route added | ||
@@ -30,0 +30,0 @@ // 🟠 AUTHORIZED - Specific user roles |
| import express from 'express'; | ||
| import organizationController from '../controllers/organizationController.js'; | ||
| // Import authentication and authorization middleware | ||
| import { validateApiKey } from '../middleware/validateApiKey.js'; | ||
| import { validateApiKey } from '../../../../middleware/validateApiKey.js'; | ||
| import { authenticateToken } from '@semantq/auth/lib/middleware/authMiddleware.js'; | ||
@@ -23,7 +23,7 @@ import { authorize } from '@semantq/auth/lib/middleware/authorize.js'; | ||
| // 🟡 AUTHENTICATED - Logged-in users only | ||
| router.get('/organizations', authenticateToken, organizationController.getAllOrganizations); | ||
| router.get('/organizations/:id', authenticateToken, organizationController.getOrganizationById); | ||
| router.post('/organizations', authenticateToken, organizationController.createOrganization); | ||
| router.put('/organizations/:id', authenticateToken, organizationController.updateOrganization); | ||
| router.delete('/organizations/:id', authenticateToken, organizationController.deleteOrganization); // 🆕 DELETE route added | ||
| router.get('/organization/organizations', authenticateToken, organizationController.getAllOrganizations); | ||
| router.get('/organization/organizations/:id', authenticateToken, organizationController.getOrganizationById); | ||
| router.post('/organization/organizations', authenticateToken, organizationController.createOrganization); | ||
| router.put('/organization/organizations/:id', authenticateToken, organizationController.updateOrganization); | ||
| router.delete('/organization/organizations/:id', authenticateToken, organizationController.deleteOrganization); // 🆕 DELETE route added | ||
@@ -30,0 +30,0 @@ // 🟠 AUTHORIZED - Specific user roles |
| import express from 'express'; | ||
| import pricingPackageFeatureController from '../controllers/pricingPackageFeatureController.js'; | ||
| // Import authentication and authorization middleware | ||
| import { validateApiKey } from '../middleware/validateApiKey.js'; | ||
| import { validateApiKey } from '../../../../middleware/validateApiKey.js'; | ||
| import { authenticateToken } from '@semantq/auth/lib/middleware/authMiddleware.js'; | ||
@@ -23,7 +23,7 @@ import { authorize } from '@semantq/auth/lib/middleware/authorize.js'; | ||
| // 🟡 AUTHENTICATED - Logged-in users only | ||
| router.get('/pricingPackageFeatures', authenticateToken, pricingPackageFeatureController.getAllPricingPackageFeatures); | ||
| router.get('/pricingPackageFeatures/:id', authenticateToken, pricingPackageFeatureController.getPricingPackageFeatureById); | ||
| router.post('/pricingPackageFeatures', authenticateToken, pricingPackageFeatureController.createPricingPackageFeature); | ||
| router.put('/pricingPackageFeatures/:id', authenticateToken, pricingPackageFeatureController.updatePricingPackageFeature); | ||
| router.delete('/pricingPackageFeatures/:id', authenticateToken, pricingPackageFeatureController.deletePricingPackageFeature); // 🆕 DELETE route added | ||
| router.get('/pricingPackageFeature/pricingPackageFeatures', authenticateToken, pricingPackageFeatureController.getAllPricingPackageFeatures); | ||
| router.get('/pricingPackageFeature/pricingPackageFeatures/:id', authenticateToken, pricingPackageFeatureController.getPricingPackageFeatureById); | ||
| router.post('/pricingPackageFeature/pricingPackageFeatures', authenticateToken, pricingPackageFeatureController.createPricingPackageFeature); | ||
| router.put('/pricingPackageFeature/pricingPackageFeatures/:id', authenticateToken, pricingPackageFeatureController.updatePricingPackageFeature); | ||
| router.delete('/pricingPackageFeature/pricingPackageFeatures/:id', authenticateToken, pricingPackageFeatureController.deletePricingPackageFeature); // 🆕 DELETE route added | ||
@@ -30,0 +30,0 @@ // 🟠 AUTHORIZED - Specific user roles |
| import express from 'express'; | ||
| import pylonController from '../controllers/pylonController.js'; | ||
| // Import authentication and authorization middleware | ||
| import { validateApiKey } from '../middleware/validateApiKey.js'; | ||
| import { authenticateToken } from '@semantq/auth/lib/middleware/authMiddleware.js'; | ||
| import { authorize } from '@semantq/auth/lib/middleware/authorize.js'; | ||
| import { validateApiKey } from '../../../../middleware/validateApiKey.js'; | ||
| import { authenticateToken } from '../../../@semantq/auth/lib/middleware/authMiddleware.js'; | ||
| import { authorize } from '../../../@semantq/auth/lib/middleware/authorize.js'; | ||
@@ -8,0 +8,0 @@ const router = express.Router(); |
@@ -1,2 +0,2 @@ | ||
| import FeatureModel from '../models/supabase/Feature.js'; | ||
| import FeatureModel from '../models/mysql/Feature.js'; | ||
@@ -9,11 +9,9 @@ class FeatureService { | ||
| async getById(id) { | ||
| const feature = await FeatureModel.findById(id); | ||
| if (!feature) throw new Error('Feature not found'); | ||
| return feature; | ||
| return await FeatureModel.findById(id); | ||
| } | ||
| async getByName(name) { | ||
| const feature = await FeatureModel.findByName(name); | ||
| if (!feature) throw new Error('Feature not found'); | ||
| return feature; | ||
| // getNonCrudFeatureNames | ||
| async getNonCrudFeatureNames() { | ||
| return await FeatureModel.getNonCrudFeatureNames(); | ||
| } | ||
@@ -26,3 +24,2 @@ | ||
| async update(id, data) { | ||
| await this.getById(id); // Verify exists | ||
| return await FeatureModel.update(id, data); | ||
@@ -32,3 +29,2 @@ } | ||
| async delete(id) { | ||
| await this.getById(id); // Verify exists | ||
| return await FeatureModel.delete(id); | ||
@@ -35,0 +31,0 @@ } |
@@ -1,4 +0,5 @@ | ||
| import MeteringModel from '../models/supabase/Metering.js'; | ||
| import MeteringModel from '../models/mysql/Metering.js'; | ||
| class MeteringService { | ||
| async create(data) { | ||
@@ -34,2 +35,3 @@ return await MeteringModel.create(data); | ||
| /* | ||
| // Pylon-specific methods | ||
@@ -43,4 +45,6 @@ async getUsage(organizationId, featureId) { | ||
| } | ||
| */ | ||
| } | ||
| export default new MeteringService(); |
@@ -1,3 +0,3 @@ | ||
| import ModelModel from '../models/supabase/Model.js'; | ||
| import ModelsManifest from '../lib/models_manifest.js'; | ||
| import ModelModel from '../models/mysql/Model.js'; | ||
| import ModelsManifest from '../../../../lib/models_manifest.js'; | ||
@@ -4,0 +4,0 @@ class ModelService { |
@@ -1,6 +0,47 @@ | ||
| import OrganizationModel from '../models/supabase/Organization.js'; | ||
| import OrganizationModel from '../models/mysql/Organization.js'; | ||
| import PricingPackageModel from '../models/mysql/PricingPackage.js'; | ||
| // | ||
| import UserModel from '../../../../models/mysql/User.js'; | ||
| class OrganizationService { | ||
| async create(data) { | ||
| return await OrganizationModel.create(data); | ||
| const { name, pricingPackageId, ownerId } = data; | ||
| // Get pricing package details | ||
| const pricingPackage = await PricingPackageModel.findById(pricingPackageId); | ||
| if (!pricingPackage) { | ||
| throw new Error('Pricing package not found'); | ||
| } | ||
| const now = new Date(); | ||
| let finalData = { ...data }; | ||
| // Check if it's a free package (both prices are 0 or less than 1) | ||
| const isFreePackage = | ||
| (!pricingPackage.priceMonthly || pricingPackage.priceMonthly < 1) && | ||
| (!pricingPackage.priceYearly || pricingPackage.priceYearly < 1); | ||
| if (isFreePackage) { | ||
| // For free packages, activate immediately with 1-year period | ||
| finalData.paidPeriodStart = now; | ||
| finalData.paidPeriodEnd = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate()); | ||
| console.log('Creating free package with automatic activation'); | ||
| } else { | ||
| // For paid packages, set trial period (30 days) | ||
| finalData.trialStartedAt = now; | ||
| finalData.trialEndsAt = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); // 30 days | ||
| console.log('Creating paid package with trial period'); | ||
| } | ||
| // Create the organization | ||
| const organization = await OrganizationModel.create(finalData); | ||
| const userUpdate = await UserModel.updateOrgId(organization.ownerId, organization.id); | ||
| //console.log("organization data",organization); | ||
| return organization; | ||
| } | ||
@@ -7,0 +48,0 @@ |
@@ -1,2 +0,2 @@ | ||
| import PricingPackageFeatureModel from '../models/supabase/PricingPackageFeature.js'; | ||
| import PricingPackageFeatureModel from '../models/mysql/PricingPackageFeature.js'; | ||
@@ -3,0 +3,0 @@ class PricingPackageFeatureService { |
| //models/supabase/Pylon.js | ||
| // Add to your schema.prisma: | ||
| /* | ||
| model Pylon { | ||
| id String @id @default(uuid()) | ||
| name String | ||
| createdAt DateTime @default(now()) | ||
| updatedAt DateTime @updatedAt | ||
| // Add additional fields as needed | ||
| } | ||
| */ | ||
| // Import the function that returns the Prisma client promise | ||
| import getPrismaClient from '../../lib/prisma.js'; | ||
| export default class PylonModel { | ||
| /** | ||
| * Creates a new pylon in the database. | ||
| * @param {object} data - The data for the new pylon. | ||
| * @returns {Promise<object>} The created pylon object. | ||
| */ | ||
| static async create(data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.create({ data }); | ||
| } | ||
| /** | ||
| * Finds a pylon by its unique ID. | ||
| * @param {string} id - The ID of the pylon to find. | ||
| * @returns {Promise<object|null>} The found pylon object, or null if not found. | ||
| */ | ||
| static async findById(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.findUnique({ where: { id } }); | ||
| } | ||
| /** | ||
| * Retrieves all pylons from the database. | ||
| * @returns {Promise<Array<object>>} An array of all pylon objects. | ||
| */ | ||
| static async findAll() { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.findMany(); | ||
| } | ||
| /** | ||
| * Updates an existing pylon by its ID. | ||
| * @param {string} id - The ID of the pylon to update. | ||
| * @param {object} data - The data to update the pylon with. | ||
| * @returns {Promise<object>} The updated pylon object. | ||
| */ | ||
| static async update(id, data) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.update({ | ||
| where: { id }, | ||
| data, | ||
| }); | ||
| } | ||
| /** | ||
| * Deletes a pylon by its ID. | ||
| * @param {string} id - The ID of the pylon to delete. | ||
| * @returns {Promise<object>} The deleted pylon object. | ||
| */ | ||
| static async delete(id) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.delete({ where: { id } }); | ||
| } | ||
| /** | ||
| * Finds pylons with pagination. | ||
| * @param {number} [skip=0] - The number of records to skip. | ||
| * @param {number} [take=10] - The number of records to take. | ||
| * @returns {Promise<Array<object>>} An array of pylon objects for the given pagination. | ||
| */ | ||
| static async findWithPagination(skip = 0, take = 10) { | ||
| const prisma = await getPrismaClient(); // Get the initialized Prisma client | ||
| return prisma.pylon.findMany({ | ||
| skip, | ||
| take, | ||
| orderBy: { createdAt: 'desc' }, // Assuming 'createdAt' field exists for ordering | ||
| }); | ||
| } | ||
| } |
89455
67.72%38
35.71%2110
89.41%