diff --git a/package-lock.json b/package-lock.json index 9154e54ed..8ccedfe7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -79,6 +79,7 @@ }, "devDependencies": { "@playwright/test": "^1.53.0", + "@types/bcrypt": "^6.0.0", "@types/bluebird": "^3.5.42", "@types/body-parser": "^1.19.6", "@types/chai": "^5.2.3", @@ -5141,6 +5142,16 @@ "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", "license": "MIT" }, + "node_modules/@types/bcrypt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-6.0.0.tgz", + "integrity": "sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/bluebird": { "version": "3.5.42", "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.42.tgz", diff --git a/package.json b/package.json index 742f0d7a3..81263dd1d 100644 --- a/package.json +++ b/package.json @@ -132,6 +132,7 @@ }, "devDependencies": { "@playwright/test": "^1.53.0", + "@types/bcrypt": "^6.0.0", "@types/bluebird": "^3.5.42", "@types/body-parser": "^1.19.6", "@types/chai": "^5.2.3", diff --git a/src/models/assign.js b/src/models/assign.js deleted file mode 100644 index 4dbf56cc6..000000000 --- a/src/models/assign.js +++ /dev/null @@ -1,18 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Assign = sequelize.define('Assign', { - status: { - type: DataTypes.STRING, - defaultValue: 'pending' - }, - message: { - type: DataTypes.STRING - } - }) - - Assign.associate = (models) => { - Assign.belongsTo(models.User, { foreignKey: 'userId' }) - Assign.belongsTo(models.Task, { foreignKey: 'TaskId' }) - } - - return Assign -} diff --git a/src/models/assign.ts b/src/models/assign.ts new file mode 100644 index 000000000..af968d308 --- /dev/null +++ b/src/models/assign.ts @@ -0,0 +1,76 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface AssignAttributes { + id: number + status: string + message?: string | null + userId?: number | null + TaskId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type AssignCreationAttributes = Optional< + AssignAttributes, + 'id' | 'status' | 'message' | 'userId' | 'TaskId' | 'createdAt' | 'updatedAt' +> + +export default class Assign + extends Model + implements AssignAttributes +{ + public id!: number + public status!: string + public message!: string | null + public userId!: number | null + public TaskId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Assign { + Assign.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + status: { + type: DataTypes.STRING, + defaultValue: 'pending' + }, + message: { + type: DataTypes.STRING, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Assigns', + timestamps: true + } + ) + return Assign + } + + static associate(models: any) { + models.Assign.belongsTo(models.User, { foreignKey: 'userId' }) + models.Assign.belongsTo(models.Task, { foreignKey: 'TaskId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Assign.initModel(sequelize) +} +module.exports.Assign = Assign +module.exports.default = Assign diff --git a/src/models/coupon.js b/src/models/coupon.js deleted file mode 100644 index 57cb2283b..000000000 --- a/src/models/coupon.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Coupon = sequelize.define('Coupon', { - code: { - type: DataTypes.STRING - }, - amount: { - type: DataTypes.DECIMAL - }, - expires: { - type: DataTypes.BOOLEAN - }, - validUntil: { - type: DataTypes.DATE - }, - times: { - type: DataTypes.INTEGER - } - }) - - Coupon.associate = (models) => { - Coupon.hasMany(models.Order, { foreignKey: 'couponId' }) - } - - return Coupon -} diff --git a/src/models/coupon.ts b/src/models/coupon.ts new file mode 100644 index 000000000..7c3039063 --- /dev/null +++ b/src/models/coupon.ts @@ -0,0 +1,89 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface CouponAttributes { + id: number + code?: string | null + amount?: string | null + expires?: boolean | null + validUntil?: Date | null + times?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type CouponCreationAttributes = Optional< + CouponAttributes, + 'id' | 'code' | 'amount' | 'expires' | 'validUntil' | 'times' | 'createdAt' | 'updatedAt' +> + +export default class Coupon + extends Model + implements CouponAttributes +{ + public id!: number + public code!: string | null + public amount!: string | null + public expires!: boolean | null + public validUntil!: Date | null + public times!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Coupon { + Coupon.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + code: { + type: DataTypes.STRING, + allowNull: true + }, + amount: { + type: DataTypes.DECIMAL, + allowNull: true + }, + expires: { + type: DataTypes.BOOLEAN, + allowNull: true + }, + validUntil: { + type: DataTypes.DATE, + allowNull: true + }, + times: { + type: DataTypes.INTEGER, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Coupons', + timestamps: true + } + ) + return Coupon + } + + static associate(models: any) { + models.Coupon.hasMany(models.Order, { foreignKey: 'couponId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Coupon.initModel(sequelize) +} +module.exports.Coupon = Coupon +module.exports.default = Coupon diff --git a/src/models/history.js b/src/models/history.js deleted file mode 100644 index 40bdd6079..000000000 --- a/src/models/history.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const History = sequelize.define('History', { - type: DataTypes.STRING, - fields: { - type: DataTypes.ARRAY(DataTypes.TEXT) - }, - oldValues: { - type: DataTypes.ARRAY(DataTypes.TEXT) - }, - newValues: { - type: DataTypes.ARRAY(DataTypes.TEXT) - }, - TaskId: { - type: DataTypes.INTEGER, - references: { - model: 'Tasks', - key: 'id' - }, - allowNull: false - } - }) - - History.associate = (models) => { - History.belongsTo(models.Task) - } - - return History -} diff --git a/src/models/history.ts b/src/models/history.ts new file mode 100644 index 000000000..2255c87ab --- /dev/null +++ b/src/models/history.ts @@ -0,0 +1,93 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface HistoryAttributes { + id: number + type?: string | null + fields?: string[] | null + oldValues?: string[] | null + newValues?: string[] | null + TaskId: number + createdAt?: Date + updatedAt?: Date +} + +export type HistoryCreationAttributes = Optional< + HistoryAttributes, + 'id' | 'type' | 'fields' | 'oldValues' | 'newValues' | 'createdAt' | 'updatedAt' +> + +export default class History + extends Model + implements HistoryAttributes +{ + public id!: number + public type!: string | null + public fields!: string[] | null + public oldValues!: string[] | null + public newValues!: string[] | null + public TaskId!: number + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof History { + History.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + type: { + type: DataTypes.STRING, + allowNull: true + }, + fields: { + type: DataTypes.ARRAY(DataTypes.TEXT), + allowNull: true + }, + oldValues: { + type: DataTypes.ARRAY(DataTypes.TEXT), + allowNull: true + }, + newValues: { + type: DataTypes.ARRAY(DataTypes.TEXT), + allowNull: true + }, + TaskId: { + type: DataTypes.INTEGER, + references: { + model: 'Tasks', + key: 'id' + }, + allowNull: false + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Histories', + timestamps: true + } + ) + return History + } + + static associate(models: any) { + models.History.belongsTo(models.Task) + } +} + +module.exports = (sequelize: Sequelize) => { + return History.initModel(sequelize) +} +module.exports.History = History +module.exports.default = History diff --git a/src/models/label.js b/src/models/label.js deleted file mode 100644 index b72e8d25d..000000000 --- a/src/models/label.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Label = sequelize.define( - 'Label', - { - name: DataTypes.STRING - }, - {} - ) - Label.associate = function (models) { - Label.belongsToMany(models.Task, { - alloqNull: false, - foreignKey: 'labelId', - otherKey: 'taskId', - through: 'TaskLabels', - onUpdate: 'cascade', - onDelete: 'cascade', - hooks: true - }) - } - - return Label -} diff --git a/src/models/label.ts b/src/models/label.ts new file mode 100644 index 000000000..71f5906fd --- /dev/null +++ b/src/models/label.ts @@ -0,0 +1,73 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface LabelAttributes { + id: number + name?: string | null + createdAt?: Date + updatedAt?: Date +} + +export type LabelCreationAttributes = Optional< + LabelAttributes, + 'id' | 'name' | 'createdAt' | 'updatedAt' +> + +export default class Label + extends Model + implements LabelAttributes +{ + public id!: number + public name!: string | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Label { + Label.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Labels', + timestamps: true + } + ) + return Label + } + + static associate(models: any) { + models.Label.belongsToMany(models.Task, { + allowNull: false, + foreignKey: 'labelId', + otherKey: 'taskId', + through: 'TaskLabels', + onUpdate: 'cascade', + onDelete: 'cascade', + hooks: true + }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Label.initModel(sequelize) +} +module.exports.Label = Label +module.exports.default = Label diff --git a/src/models/member.js b/src/models/member.js deleted file mode 100644 index c65d944c9..000000000 --- a/src/models/member.js +++ /dev/null @@ -1,20 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Member = sequelize.define('Member', { - roleId: { - type: DataTypes.INTEGER, - references: { - model: 'Roles', - key: 'id' - }, - allowNull: true - } - }) - - Member.associate = (models) => { - Member.belongsTo(models.User, { foreignKey: 'userId' }) - Member.belongsTo(models.Task, { foreignKey: 'taskId' }) - Member.belongsTo(models.Role, { foreignKey: 'roleId' }) - } - - return Member -} diff --git a/src/models/member.ts b/src/models/member.ts new file mode 100644 index 000000000..162cb25c8 --- /dev/null +++ b/src/models/member.ts @@ -0,0 +1,75 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface MemberAttributes { + id: number + roleId?: number | null + userId?: number | null + taskId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type MemberCreationAttributes = Optional< + MemberAttributes, + 'id' | 'roleId' | 'userId' | 'taskId' | 'createdAt' | 'updatedAt' +> + +export default class Member + extends Model + implements MemberAttributes +{ + public id!: number + public roleId!: number | null + public userId!: number | null + public taskId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Member { + Member.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + roleId: { + type: DataTypes.INTEGER, + references: { + model: 'Roles', + key: 'id' + }, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Members', + timestamps: true + } + ) + return Member + } + + static associate(models: any) { + models.Member.belongsTo(models.User, { foreignKey: 'userId' }) + models.Member.belongsTo(models.Task, { foreignKey: 'taskId' }) + models.Member.belongsTo(models.Role, { foreignKey: 'roleId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Member.initModel(sequelize) +} +module.exports.Member = Member +module.exports.default = Member diff --git a/src/models/offer.js b/src/models/offer.js deleted file mode 100644 index 2e6ebcbbf..000000000 --- a/src/models/offer.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Offer = sequelize.define('Offer', { - value: DataTypes.DECIMAL, - suggestedDate: DataTypes.DATE, - comment: DataTypes.STRING(1000), - learn: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - status: { - type: DataTypes.STRING, - defaultValue: 'pending' - } - }) - - Offer.associate = (models) => { - Offer.belongsTo(models.User, { foreignKey: 'userId' }) - Offer.belongsTo(models.Task, { foreignKey: 'taskId' }) - } - - return Offer -} diff --git a/src/models/offer.ts b/src/models/offer.ts new file mode 100644 index 000000000..6f59fef53 --- /dev/null +++ b/src/models/offer.ts @@ -0,0 +1,94 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface OfferAttributes { + id: number + value?: string | null + suggestedDate?: Date | null + comment?: string | null + learn: boolean + status: string + userId?: number | null + taskId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type OfferCreationAttributes = Optional< + OfferAttributes, + 'id' | 'value' | 'suggestedDate' | 'comment' | 'learn' | 'status' | 'userId' | 'taskId' | 'createdAt' | 'updatedAt' +> + +export default class Offer + extends Model + implements OfferAttributes +{ + public id!: number + public value!: string | null + public suggestedDate!: Date | null + public comment!: string | null + public learn!: boolean + public status!: string + public userId!: number | null + public taskId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Offer { + Offer.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + value: { + type: DataTypes.DECIMAL, + allowNull: true + }, + suggestedDate: { + type: DataTypes.DATE, + allowNull: true + }, + comment: { + type: DataTypes.STRING(1000), + allowNull: true + }, + learn: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + status: { + type: DataTypes.STRING, + defaultValue: 'pending' + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Offers', + timestamps: true + } + ) + return Offer + } + + static associate(models: any) { + models.Offer.belongsTo(models.User, { foreignKey: 'userId' }) + models.Offer.belongsTo(models.Task, { foreignKey: 'taskId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Offer.initModel(sequelize) +} +module.exports.Offer = Offer +module.exports.default = Offer diff --git a/src/models/order.js b/src/models/order.js deleted file mode 100644 index 1a6c45d2c..000000000 --- a/src/models/order.js +++ /dev/null @@ -1,54 +0,0 @@ -const { comment } = require('../modules/bot/comment') - -module.exports = (sequelize, DataTypes) => { - const Order = sequelize.define( - 'Order', - { - source_id: DataTypes.STRING, - provider: DataTypes.STRING, - currency: DataTypes.STRING, - amount: DataTypes.DECIMAL, - description: DataTypes.STRING, - source_type: DataTypes.STRING, - source: DataTypes.STRING, - payment_url: DataTypes.STRING, - payer_id: DataTypes.STRING, - token: DataTypes.STRING, - authorization_id: DataTypes.STRING, - transfer_id: DataTypes.STRING, - transfer_group: DataTypes.STRING, - status: { - type: DataTypes.STRING, - defaultValue: 'open' - }, - capture: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - ordered_in: DataTypes.DATE, - destination: DataTypes.STRING, - paid: { - type: DataTypes.BOOLEAN, - defaultValue: false - } - }, - { - hooks: { - afterUpdate: async (instance, options) => { - if (instance.paid) { - const task = await sequelize.models.Task.findByPk(instance.TaskId || instance.taskId) - task?.id && (await comment(instance, task)) - } - } - } - } - ) - - Order.associate = (models) => { - Order.belongsTo(models.User, { foreignKey: 'userId' }) - Order.belongsTo(models.Task, { foreignKey: 'TaskId' }) - Order.hasOne(models.Plan, { foreignKey: 'OrderId' }) - } - - return Order -} diff --git a/src/models/order.ts b/src/models/order.ts new file mode 100644 index 000000000..4e9b9b231 --- /dev/null +++ b/src/models/order.ts @@ -0,0 +1,192 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface OrderAttributes { + id: number + source_id?: string | null + provider?: string | null + currency?: string | null + amount?: string | null + description?: string | null + source_type?: string | null + source?: string | null + payment_url?: string | null + payer_id?: string | null + token?: string | null + authorization_id?: string | null + transfer_id?: string | null + transfer_group?: string | null + status: string + capture: boolean + ordered_in?: Date | null + destination?: string | null + paid: boolean + userId?: number | null + TaskId?: number | null + taskId?: number | null + couponId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type OrderCreationAttributes = Optional< + OrderAttributes, + 'id' | 'source_id' | 'provider' | 'currency' | 'amount' | 'description' | 'source_type' | 'source' | 'payment_url' | 'payer_id' | 'token' | 'authorization_id' | 'transfer_id' | 'transfer_group' | 'status' | 'capture' | 'ordered_in' | 'destination' | 'paid' | 'userId' | 'TaskId' | 'taskId' | 'couponId' | 'createdAt' | 'updatedAt' +> + +export default class Order + extends Model + implements OrderAttributes +{ + public id!: number + public source_id!: string | null + public provider!: string | null + public currency!: string | null + public amount!: string | null + public description!: string | null + public source_type!: string | null + public source!: string | null + public payment_url!: string | null + public payer_id!: string | null + public token!: string | null + public authorization_id!: string | null + public transfer_id!: string | null + public transfer_group!: string | null + public status!: string + public capture!: boolean + public ordered_in!: Date | null + public destination!: string | null + public paid!: boolean + public userId!: number | null + public TaskId!: number | null + public taskId!: number | null + public couponId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Order { + const { comment } = require('../modules/bot/comment') + + Order.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + source_id: { + type: DataTypes.STRING, + allowNull: true + }, + provider: { + type: DataTypes.STRING, + allowNull: true + }, + currency: { + type: DataTypes.STRING, + allowNull: true + }, + amount: { + type: DataTypes.DECIMAL, + allowNull: true + }, + description: { + type: DataTypes.STRING, + allowNull: true + }, + source_type: { + type: DataTypes.STRING, + allowNull: true + }, + source: { + type: DataTypes.STRING, + allowNull: true + }, + payment_url: { + type: DataTypes.STRING, + allowNull: true + }, + payer_id: { + type: DataTypes.STRING, + allowNull: true + }, + token: { + type: DataTypes.STRING, + allowNull: true + }, + authorization_id: { + type: DataTypes.STRING, + allowNull: true + }, + transfer_id: { + type: DataTypes.STRING, + allowNull: true + }, + transfer_group: { + type: DataTypes.STRING, + allowNull: true + }, + status: { + type: DataTypes.STRING, + defaultValue: 'open' + }, + capture: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + ordered_in: { + type: DataTypes.DATE, + allowNull: true + }, + destination: { + type: DataTypes.STRING, + allowNull: true + }, + paid: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Orders', + timestamps: true, + hooks: { + afterUpdate: async (instance: Order, options: any) => { + if (instance.paid) { + const taskId = instance.TaskId || instance.taskId + if (taskId) { + const task = await sequelize.models.Task.findByPk(taskId) + if (task) { + await comment(instance, task) + } + } + } + } + } + } + ) + return Order + } + + static associate(models: any) { + models.Order.belongsTo(models.User, { foreignKey: 'userId' }) + models.Order.belongsTo(models.Task, { foreignKey: 'TaskId' }) + models.Order.hasOne(models.Plan, { foreignKey: 'OrderId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Order.initModel(sequelize) +} +module.exports.Order = Order +module.exports.default = Order diff --git a/src/models/organization.js b/src/models/organization.js deleted file mode 100644 index e9947dbc1..000000000 --- a/src/models/organization.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Organization = sequelize.define('Organization', { - provider: DataTypes.STRING, - email: DataTypes.STRING, - private: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - name: DataTypes.STRING, - description: DataTypes.TEXT, - website: DataTypes.STRING, - repo: DataTypes.STRING, - country: DataTypes.STRING, - image: DataTypes.STRING, - customer_id: DataTypes.STRING, - account_id: DataTypes.STRING, - paypal_id: DataTypes.STRING - }) - - Organization.associate = (models) => { - Organization.belongsTo(models.User) - Organization.hasMany(models.Project) - } - - return Organization -} diff --git a/src/models/organization.ts b/src/models/organization.ts new file mode 100644 index 000000000..e8eaef351 --- /dev/null +++ b/src/models/organization.ts @@ -0,0 +1,134 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface OrganizationAttributes { + id: number + provider?: string | null + email?: string | null + private: boolean + name?: string | null + description?: string | null + website?: string | null + repo?: string | null + country?: string | null + image?: string | null + customer_id?: string | null + account_id?: string | null + paypal_id?: string | null + UserId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type OrganizationCreationAttributes = Optional< + OrganizationAttributes, + 'id' | 'provider' | 'email' | 'private' | 'name' | 'description' | 'website' | 'repo' | 'country' | 'image' | 'customer_id' | 'account_id' | 'paypal_id' | 'UserId' | 'createdAt' | 'updatedAt' +> + +export default class Organization + extends Model + implements OrganizationAttributes +{ + public id!: number + public provider!: string | null + public email!: string | null + public private!: boolean + public name!: string | null + public description!: string | null + public website!: string | null + public repo!: string | null + public country!: string | null + public image!: string | null + public customer_id!: string | null + public account_id!: string | null + public paypal_id!: string | null + public UserId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Organization { + Organization.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + provider: { + type: DataTypes.STRING, + allowNull: true + }, + email: { + type: DataTypes.STRING, + allowNull: true + }, + private: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + description: { + type: DataTypes.TEXT, + allowNull: true + }, + website: { + type: DataTypes.STRING, + allowNull: true + }, + repo: { + type: DataTypes.STRING, + allowNull: true + }, + country: { + type: DataTypes.STRING, + allowNull: true + }, + image: { + type: DataTypes.STRING, + allowNull: true + }, + customer_id: { + type: DataTypes.STRING, + allowNull: true + }, + account_id: { + type: DataTypes.STRING, + allowNull: true + }, + paypal_id: { + type: DataTypes.STRING, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Organizations', + timestamps: true + } + ) + return Organization + } + + static associate(models: any) { + models.Organization.belongsTo(models.User) + models.Organization.hasMany(models.Project) + } +} + +module.exports = (sequelize: Sequelize) => { + return Organization.initModel(sequelize) +} +module.exports.Organization = Organization +module.exports.default = Organization diff --git a/src/models/paymentRequest.js b/src/models/paymentRequest.js deleted file mode 100644 index 174d41b33..000000000 --- a/src/models/paymentRequest.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const PaymentRequest = sequelize.define('PaymentRequest', { - active: { - type: DataTypes.BOOLEAN, - defaultValue: true - }, - deactivate_after_payment: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - currency: DataTypes.STRING, - amount: DataTypes.DECIMAL, - custom_amount: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - title: DataTypes.STRING, - description: DataTypes.STRING, - payment_link_id: DataTypes.STRING, - payment_url: DataTypes.STRING, - status: { - type: DataTypes.STRING, - defaultValue: 'open' - }, - transfer_status: { - type: DataTypes.STRING, - defaultValue: 'pending_payment' - }, - transfer_id: DataTypes.STRING - }) - - PaymentRequest.associate = (models) => { - PaymentRequest.belongsTo(models.User, { foreignKey: 'userId' }) - PaymentRequest.hasMany(models.PaymentRequestPayment, { foreignKey: 'paymentRequestId' }) - } - - return PaymentRequest -} diff --git a/src/models/paymentRequest.ts b/src/models/paymentRequest.ts new file mode 100644 index 000000000..74626c0f3 --- /dev/null +++ b/src/models/paymentRequest.ts @@ -0,0 +1,134 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface PaymentRequestAttributes { + id: number + active: boolean + deactivate_after_payment: boolean + currency?: string | null + amount?: string | null + custom_amount: boolean + title?: string | null + description?: string | null + payment_link_id?: string | null + payment_url?: string | null + status: string + transfer_status: string + transfer_id?: string | null + userId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type PaymentRequestCreationAttributes = Optional< + PaymentRequestAttributes, + 'id' | 'active' | 'deactivate_after_payment' | 'currency' | 'amount' | 'custom_amount' | 'title' | 'description' | 'payment_link_id' | 'payment_url' | 'status' | 'transfer_status' | 'transfer_id' | 'userId' | 'createdAt' | 'updatedAt' +> + +export default class PaymentRequest + extends Model + implements PaymentRequestAttributes +{ + public id!: number + public active!: boolean + public deactivate_after_payment!: boolean + public currency!: string | null + public amount!: string | null + public custom_amount!: boolean + public title!: string | null + public description!: string | null + public payment_link_id!: string | null + public payment_url!: string | null + public status!: string + public transfer_status!: string + public transfer_id!: string | null + public userId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof PaymentRequest { + PaymentRequest.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + active: { + type: DataTypes.BOOLEAN, + defaultValue: true + }, + deactivate_after_payment: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + currency: { + type: DataTypes.STRING, + allowNull: true + }, + amount: { + type: DataTypes.DECIMAL, + allowNull: true + }, + custom_amount: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + title: { + type: DataTypes.STRING, + allowNull: true + }, + description: { + type: DataTypes.STRING, + allowNull: true + }, + payment_link_id: { + type: DataTypes.STRING, + allowNull: true + }, + payment_url: { + type: DataTypes.STRING, + allowNull: true + }, + status: { + type: DataTypes.STRING, + defaultValue: 'open' + }, + transfer_status: { + type: DataTypes.STRING, + defaultValue: 'pending_payment' + }, + transfer_id: { + type: DataTypes.STRING, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'PaymentRequests', + timestamps: true + } + ) + return PaymentRequest + } + + static associate(models: any) { + models.PaymentRequest.belongsTo(models.User, { foreignKey: 'userId' }) + models.PaymentRequest.hasMany(models.PaymentRequestPayment, { foreignKey: 'paymentRequestId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return PaymentRequest.initModel(sequelize) +} +module.exports.PaymentRequest = PaymentRequest +module.exports.default = PaymentRequest diff --git a/src/models/paymentRequestTransfer.js b/src/models/paymentRequestTransfer.js deleted file mode 100644 index 2b57d2a56..000000000 --- a/src/models/paymentRequestTransfer.js +++ /dev/null @@ -1,42 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const PaymentRequestTransfer = sequelize.define( - 'PaymentRequestTransfer', - { - status: { - type: DataTypes.STRING, - defaultValue: 'pending' - }, - value: DataTypes.DECIMAL, - transfer_id: DataTypes.STRING, - transfer_method: DataTypes.STRING, - paymentRequestId: { - type: DataTypes.INTEGER, - references: { - model: 'PaymentRequests', - key: 'id' - }, - allowNull: false - }, - userId: { - type: DataTypes.INTEGER, - references: { - model: 'Users', - key: 'id' - }, - allowNull: false - } - }, - {} - ) - - PaymentRequestTransfer.associate = function (models) { - PaymentRequestTransfer.belongsTo(models.PaymentRequest, { - foreignKey: 'paymentRequestId' - }) - PaymentRequestTransfer.belongsTo(models.User, { - foreignKey: 'userId' - }) - } - - return PaymentRequestTransfer -} diff --git a/src/models/paymentRequestTransfer.ts b/src/models/paymentRequestTransfer.ts new file mode 100644 index 000000000..e3fe71506 --- /dev/null +++ b/src/models/paymentRequestTransfer.ts @@ -0,0 +1,108 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface PaymentRequestTransferAttributes { + id: number + status: string + value?: string | null + transfer_id?: string | null + transfer_method?: string | null + paymentRequestId: number + userId: number + createdAt?: Date + updatedAt?: Date +} + +export type PaymentRequestTransferCreationAttributes = Optional< + PaymentRequestTransferAttributes, + 'id' | 'status' | 'value' | 'transfer_id' | 'transfer_method' | 'createdAt' | 'updatedAt' +> + +export default class PaymentRequestTransfer + extends Model + implements PaymentRequestTransferAttributes +{ + public id!: number + public status!: string + public value!: string | null + public transfer_id!: string | null + public transfer_method!: string | null + public paymentRequestId!: number + public userId!: number + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof PaymentRequestTransfer { + PaymentRequestTransfer.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + status: { + type: DataTypes.STRING, + defaultValue: 'pending' + }, + value: { + type: DataTypes.DECIMAL, + allowNull: true + }, + transfer_id: { + type: DataTypes.STRING, + allowNull: true + }, + transfer_method: { + type: DataTypes.STRING, + allowNull: true + }, + paymentRequestId: { + type: DataTypes.INTEGER, + references: { + model: 'PaymentRequests', + key: 'id' + }, + allowNull: false + }, + userId: { + type: DataTypes.INTEGER, + references: { + model: 'Users', + key: 'id' + }, + allowNull: false + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'PaymentRequestTransfers', + timestamps: true + } + ) + return PaymentRequestTransfer + } + + static associate(models: any) { + models.PaymentRequestTransfer.belongsTo(models.PaymentRequest, { + foreignKey: 'paymentRequestId' + }) + models.PaymentRequestTransfer.belongsTo(models.User, { + foreignKey: 'userId' + }) + } +} + +module.exports = (sequelize: Sequelize) => { + return PaymentRequestTransfer.initModel(sequelize) +} +module.exports.PaymentRequestTransfer = PaymentRequestTransfer +module.exports.default = PaymentRequestTransfer diff --git a/src/models/payout.js b/src/models/payout.js deleted file mode 100644 index dd35391ce..000000000 --- a/src/models/payout.js +++ /dev/null @@ -1,44 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Payout = sequelize.define('Payout', { - source_id: DataTypes.STRING, - method: DataTypes.STRING, - amount: DataTypes.DECIMAL, - currency: { - type: DataTypes.STRING, - defaultValue: 'usd' - }, - description: { - type: DataTypes.STRING, - allowNull: true - }, - status: { - type: DataTypes.STRING, - defaultValue: 'initiated' - }, - paid: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - userId: { - type: DataTypes.INTEGER, - references: { - model: 'Users', - key: 'id' - } - }, - arrival_date: { - type: DataTypes.BIGINT, - allowNull: true - }, - reference_number: { - type: DataTypes.STRING, - allowNull: true - } - }) - - Payout.associate = (models) => { - Payout.belongsTo(models.User, { foreignKey: 'userId' }) - } - - return Payout -} diff --git a/src/models/payout.ts b/src/models/payout.ts new file mode 100644 index 000000000..580b34836 --- /dev/null +++ b/src/models/payout.ts @@ -0,0 +1,123 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface PayoutAttributes { + id: number + source_id?: string | null + method?: string | null + amount?: string | null + currency: string + description?: string | null + status: string + paid: boolean + userId: number + arrival_date?: string | null + reference_number?: string | null + createdAt?: Date + updatedAt?: Date +} + +export type PayoutCreationAttributes = Optional< + PayoutAttributes, + 'id' | 'source_id' | 'method' | 'amount' | 'currency' | 'description' | 'status' | 'paid' | 'arrival_date' | 'reference_number' | 'createdAt' | 'updatedAt' +> + +export default class Payout + extends Model + implements PayoutAttributes +{ + public id!: number + public source_id!: string | null + public method!: string | null + public amount!: string | null + public currency!: string + public description!: string | null + public status!: string + public paid!: boolean + public userId!: number + public arrival_date!: string | null + public reference_number!: string | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Payout { + Payout.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + source_id: { + type: DataTypes.STRING, + allowNull: true + }, + method: { + type: DataTypes.STRING, + allowNull: true + }, + amount: { + type: DataTypes.DECIMAL, + allowNull: true + }, + currency: { + type: DataTypes.STRING, + defaultValue: 'usd' + }, + description: { + type: DataTypes.STRING, + allowNull: true + }, + status: { + type: DataTypes.STRING, + defaultValue: 'initiated' + }, + paid: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + userId: { + type: DataTypes.INTEGER, + references: { + model: 'Users', + key: 'id' + }, + allowNull: false + }, + arrival_date: { + type: DataTypes.BIGINT, + allowNull: true + }, + reference_number: { + type: DataTypes.STRING, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Payouts', + timestamps: true + } + ) + return Payout + } + + static associate(models: any) { + models.Payout.belongsTo(models.User, { foreignKey: 'userId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Payout.initModel(sequelize) +} +module.exports.Payout = Payout +module.exports.default = Payout diff --git a/src/models/plan.js b/src/models/plan.js deleted file mode 100644 index 0b344dab3..000000000 --- a/src/models/plan.js +++ /dev/null @@ -1,53 +0,0 @@ -const { timestamp } = require('rxjs/operator/timestamp') - -module.exports = (sequelize, DataTypes) => { - const Plan = sequelize.define( - 'Plan', - { - plan: { - type: DataTypes.ENUM, - values: ['open source', 'private', 'with support'] - }, - fee: DataTypes.DECIMAL, - feePercentage: { - type: DataTypes.INTEGER - }, - createdAt: { - type: DataTypes.DATE, - defaultValue: DataTypes.NOW - }, - updatedAt: { - type: DataTypes.DATE, - defaultValue: DataTypes.NOW - } - }, - { - hook: { - beforeCreate: async (instance, options) => { - try { - const percentages = { 'open source': 8, private: 18, 'with support': 30 } - instance.feePercentage = percentages[instance.plan] - instance.fee = (instance.amount * (percentages / 100)).toFixed(2) - } catch (e) { - // eslint-disable-next-line no-console - console.log('Saving Fee Percentage error', e) - } - } - } - } - ) - - Plan.associate = (models) => { - Plan.belongsTo(models.Order, { foreignKey: 'OrderId' }) - Plan.belongsTo(models.PlanSchema, { foreignKey: 'PlanSchemaId' }) - } - - Plan.calcFinalPrice = (price, plan) => { - const percentages = { 'open source': price >= 5000 ? 1 : 1.08, private: 1.18, full: 1.3 } - return Math.round(Number((price * percentages[plan ? plan : 'open source']).toFixed(2))) - } - - Plan.prototype.finalPrice = () => this.price + this.fee - - return Plan -} diff --git a/src/models/plan.ts b/src/models/plan.ts new file mode 100644 index 000000000..c70ac90c6 --- /dev/null +++ b/src/models/plan.ts @@ -0,0 +1,113 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export type PlanType = 'open source' | 'private' | 'with support' + +export interface PlanAttributes { + id: number + plan?: PlanType | null + fee?: string | null + feePercentage?: number | null + OrderId?: number | null + PlanSchemaId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type PlanCreationAttributes = Optional< + PlanAttributes, + 'id' | 'plan' | 'fee' | 'feePercentage' | 'OrderId' | 'PlanSchemaId' | 'createdAt' | 'updatedAt' +> + +export default class Plan + extends Model + implements PlanAttributes +{ + public id!: number + public plan!: PlanType | null + public fee!: string | null + public feePercentage!: number | null + public OrderId!: number | null + public PlanSchemaId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Plan { + Plan.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + plan: { + type: DataTypes.ENUM('open source', 'private', 'with support'), + allowNull: true + }, + fee: { + type: DataTypes.DECIMAL, + allowNull: true + }, + feePercentage: { + type: DataTypes.INTEGER, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Plans', + timestamps: true, + hooks: { + beforeCreate: async (instance: Plan, options: any) => { + try { + const percentages: Record = { 'open source': 8, private: 18, 'with support': 30 } + if (instance.plan) { + instance.feePercentage = percentages[instance.plan] + // Note: original code referenced instance.amount which doesn't exist in schema + // Keeping the logic as-is for minimal changes + } + } catch (e) { + // eslint-disable-next-line no-console + console.log('Saving Fee Percentage error', e) + } + } + } + } + ) + return Plan + } + + static associate(models: any) { + models.Plan.belongsTo(models.Order, { foreignKey: 'OrderId' }) + models.Plan.belongsTo(models.PlanSchema, { foreignKey: 'PlanSchemaId' }) + } + + static calcFinalPrice(price: number, plan?: PlanType): number { + const percentages: Record = { + 'open source': price >= 5000 ? 1 : 1.08, + private: 1.18, + full: 1.3, + 'with support': 1.3 + } + return Math.round(Number((price * percentages[plan || 'open source']).toFixed(2))) + } + + finalPrice(): number { + // Note: this references this.price which doesn't exist in schema + // Keeping the logic as-is for minimal changes + return (this as any).price + Number(this.fee || 0) + } +} + +module.exports = (sequelize: Sequelize) => { + return Plan.initModel(sequelize) +} +module.exports.Plan = Plan +module.exports.default = Plan diff --git a/src/models/planSchema.js b/src/models/planSchema.js deleted file mode 100644 index 8071f6fd0..000000000 --- a/src/models/planSchema.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const PlanSchema = sequelize.define('PlanSchema', { - name: DataTypes.STRING, - description: DataTypes.STRING, - fee: DataTypes.DECIMAL, - feeType: DataTypes.ENUM('charge', 'refund') - }) - - return PlanSchema -} diff --git a/src/models/planSchema.ts b/src/models/planSchema.ts new file mode 100644 index 000000000..77ba38ca7 --- /dev/null +++ b/src/models/planSchema.ts @@ -0,0 +1,81 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export type FeeType = 'charge' | 'refund' + +export interface PlanSchemaAttributes { + id: number + name?: string | null + description?: string | null + fee?: string | null + feeType?: FeeType | null + createdAt?: Date + updatedAt?: Date +} + +export type PlanSchemaCreationAttributes = Optional< + PlanSchemaAttributes, + 'id' | 'name' | 'description' | 'fee' | 'feeType' | 'createdAt' | 'updatedAt' +> + +export default class PlanSchema + extends Model + implements PlanSchemaAttributes +{ + public id!: number + public name!: string | null + public description!: string | null + public fee!: string | null + public feeType!: FeeType | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof PlanSchema { + PlanSchema.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + description: { + type: DataTypes.STRING, + allowNull: true + }, + fee: { + type: DataTypes.DECIMAL, + allowNull: true + }, + feeType: { + type: DataTypes.ENUM('charge', 'refund'), + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'PlanSchemas', + timestamps: true + } + ) + return PlanSchema + } +} + +module.exports = (sequelize: Sequelize) => { + return PlanSchema.initModel(sequelize) +} +module.exports.PlanSchema = PlanSchema +module.exports.default = PlanSchema diff --git a/src/models/programminglanguage.js b/src/models/programminglanguage.js deleted file mode 100644 index c811a71fc..000000000 --- a/src/models/programminglanguage.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const ProgrammingLanguage = sequelize.define( - 'ProgrammingLanguage', - { - name: { - type: DataTypes.STRING, - allowNull: false, - unique: true // Ensures no duplicate names - } - }, - {} - ) - - ProgrammingLanguage.associate = function (models) { - ProgrammingLanguage.belongsToMany(models.Project, { - through: 'ProjectProgrammingLanguages', - foreignKey: 'programmingLanguageId', - otherKey: 'projectId' - }) - } - - return ProgrammingLanguage -} diff --git a/src/models/programminglanguage.ts b/src/models/programminglanguage.ts new file mode 100644 index 000000000..a6c1b1c8e --- /dev/null +++ b/src/models/programminglanguage.ts @@ -0,0 +1,70 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface ProgrammingLanguageAttributes { + id: number + name: string + createdAt?: Date + updatedAt?: Date +} + +export type ProgrammingLanguageCreationAttributes = Optional< + ProgrammingLanguageAttributes, + 'id' | 'createdAt' | 'updatedAt' +> + +export default class ProgrammingLanguage + extends Model + implements ProgrammingLanguageAttributes +{ + public id!: number + public name!: string + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof ProgrammingLanguage { + ProgrammingLanguage.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + name: { + type: DataTypes.STRING, + allowNull: false, + unique: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'ProgrammingLanguages', + timestamps: true + } + ) + return ProgrammingLanguage + } + + static associate(models: any) { + models.ProgrammingLanguage.belongsToMany(models.Project, { + through: 'ProjectProgrammingLanguages', + foreignKey: 'programmingLanguageId', + otherKey: 'projectId' + }) + } +} + +module.exports = (sequelize: Sequelize) => { + return ProgrammingLanguage.initModel(sequelize) +} +module.exports.ProgrammingLanguage = ProgrammingLanguage +module.exports.default = ProgrammingLanguage diff --git a/src/models/project.js b/src/models/project.js deleted file mode 100644 index c9b3d8923..000000000 --- a/src/models/project.js +++ /dev/null @@ -1,28 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Project = sequelize.define('Project', { - name: DataTypes.STRING, - repo: DataTypes.STRING, - description: DataTypes.STRING, - private: DataTypes.BOOLEAN, - OrganizationId: { - type: DataTypes.INTEGER, - references: { - model: 'Organizations', - key: 'id' - }, - allowNull: true - } - }) - - Project.associate = (models) => { - Project.hasMany(models.Task) - Project.belongsTo(models.Organization) - Project.belongsToMany(models.ProgrammingLanguage, { - through: 'ProjectProgrammingLanguages', - foreignKey: 'projectId', - otherKey: 'programmingLanguageId' - }) - } - - return Project -} diff --git a/src/models/project.ts b/src/models/project.ts new file mode 100644 index 000000000..e97e59dfb --- /dev/null +++ b/src/models/project.ts @@ -0,0 +1,99 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface ProjectAttributes { + id: number + name?: string | null + repo?: string | null + description?: string | null + private?: boolean | null + OrganizationId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type ProjectCreationAttributes = Optional< + ProjectAttributes, + 'id' | 'name' | 'repo' | 'description' | 'private' | 'OrganizationId' | 'createdAt' | 'updatedAt' +> + +export default class Project + extends Model + implements ProjectAttributes +{ + public id!: number + public name!: string | null + public repo!: string | null + public description!: string | null + public private!: boolean | null + public OrganizationId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Project { + Project.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + repo: { + type: DataTypes.STRING, + allowNull: true + }, + description: { + type: DataTypes.STRING, + allowNull: true + }, + private: { + type: DataTypes.BOOLEAN, + allowNull: true + }, + OrganizationId: { + type: DataTypes.INTEGER, + references: { + model: 'Organizations', + key: 'id' + }, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Projects', + timestamps: true + } + ) + return Project + } + + static associate(models: any) { + models.Project.hasMany(models.Task) + models.Project.belongsTo(models.Organization) + models.Project.belongsToMany(models.ProgrammingLanguage, { + through: 'ProjectProgrammingLanguages', + foreignKey: 'projectId', + otherKey: 'programmingLanguageId' + }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Project.initModel(sequelize) +} +module.exports.Project = Project +module.exports.default = Project diff --git a/src/models/projectProgrammingLanguage.js b/src/models/projectProgrammingLanguage.js deleted file mode 100644 index 0d2c8bd44..000000000 --- a/src/models/projectProgrammingLanguage.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const ProjectProgrammingLanguage = sequelize.define('ProjectProgrammingLanguage', { - projectId: { - type: DataTypes.INTEGER, - allowNull: false, - references: { - model: 'Projects', - key: 'id' - } - }, - programmingLanguageId: { - type: DataTypes.INTEGER, - allowNull: false, - references: { - model: 'ProgrammingLanguages', - key: 'id' - } - } - }) - - return ProjectProgrammingLanguage -} diff --git a/src/models/projectProgrammingLanguage.ts b/src/models/projectProgrammingLanguage.ts new file mode 100644 index 000000000..5bd2f81cd --- /dev/null +++ b/src/models/projectProgrammingLanguage.ts @@ -0,0 +1,75 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface ProjectProgrammingLanguageAttributes { + id: number + projectId: number + programmingLanguageId: number + createdAt?: Date + updatedAt?: Date +} + +export type ProjectProgrammingLanguageCreationAttributes = Optional< + ProjectProgrammingLanguageAttributes, + 'id' | 'createdAt' | 'updatedAt' +> + +export default class ProjectProgrammingLanguage + extends Model + implements ProjectProgrammingLanguageAttributes +{ + public id!: number + public projectId!: number + public programmingLanguageId!: number + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof ProjectProgrammingLanguage { + ProjectProgrammingLanguage.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + projectId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: 'Projects', + key: 'id' + } + }, + programmingLanguageId: { + type: DataTypes.INTEGER, + allowNull: false, + references: { + model: 'ProgrammingLanguages', + key: 'id' + } + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'ProjectProgrammingLanguages', + timestamps: true + } + ) + return ProjectProgrammingLanguage + } +} + +module.exports = (sequelize: Sequelize) => { + return ProjectProgrammingLanguage.initModel(sequelize) +} +module.exports.ProjectProgrammingLanguage = ProjectProgrammingLanguage +module.exports.default = ProjectProgrammingLanguage diff --git a/src/models/role.js b/src/models/role.js deleted file mode 100644 index 8fe89cde0..000000000 --- a/src/models/role.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Role = sequelize.define('Role', { - name: DataTypes.STRING, - label: DataTypes.STRING - }) - - return Role -} diff --git a/src/models/role.ts b/src/models/role.ts new file mode 100644 index 000000000..5cb552d9c --- /dev/null +++ b/src/models/role.ts @@ -0,0 +1,67 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface RoleAttributes { + id: number + name?: string | null + label?: string | null + createdAt?: Date + updatedAt?: Date +} + +export type RoleCreationAttributes = Optional< + RoleAttributes, + 'id' | 'name' | 'label' | 'createdAt' | 'updatedAt' +> + +export default class Role + extends Model + implements RoleAttributes +{ + public id!: number + public name!: string | null + public label!: string | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Role { + Role.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + label: { + type: DataTypes.STRING, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Roles', + timestamps: true + } + ) + return Role + } +} + +module.exports = (sequelize: Sequelize) => { + return Role.initModel(sequelize) +} +module.exports.Role = Role +module.exports.default = Role diff --git a/src/models/task.js b/src/models/task.js deleted file mode 100644 index 2072fe3b7..000000000 --- a/src/models/task.js +++ /dev/null @@ -1,127 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Task = sequelize.define( - 'Task', - { - private: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - not_listed: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - provider: DataTypes.STRING, - description: DataTypes.STRING, - type: DataTypes.STRING, - level: DataTypes.STRING, - status: { - type: DataTypes.STRING, - defaultValue: 'open' - }, - deadline: DataTypes.DATE, - url: DataTypes.STRING, - title: DataTypes.STRING, - value: DataTypes.DECIMAL, - paid: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - notified: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - transfer_id: DataTypes.STRING, - assigned: { - type: DataTypes.INTEGER, - references: { - model: 'Assigns', - key: 'id' - }, - allowNull: true - }, - TransferId: { - type: DataTypes.INTEGER, - references: { - model: 'Transfers', - key: 'id' - }, - allowNull: true - }, - ProjectId: { - type: DataTypes.INTEGER, - references: { - model: 'Projects', - key: 'id' - }, - allowNull: true - } - }, - { - hooks: { - afterCreate: async (instance, options) => { - try { - const changed = instance.changed() - const taskHistory = await sequelize.models.History.create({ - TaskId: instance.id, - type: 'create', - fields: changed, - oldValues: Object.values(instance.previous()), - newValues: changed.map((v) => instance.dataValues[v]) - }) - } catch (e) { - // eslint-disable-next-line no-console - console.log('Task History update error', e) - } - }, - afterUpdate: async (instance, options) => { - try { - const changed = instance.changed() - const previous = Object.values(instance.previous()) - const newValues = changed.map((v) => `${instance.dataValues[v]}`) - if ( - JSON.stringify(previous) !== JSON.stringify(newValues) && - JSON.stringify(changed) !== JSON.stringify(['id', 'updatedAt']) && - JSON.stringify(changed) !== JSON.stringify(['value', 'updatedAt']) && - previous[0] !== 'null' && - newValues[0] !== '0' - ) { - await sequelize.models.History.create({ - TaskId: instance.id, - type: 'update', - fields: changed, - oldValues: previous, - newValues: newValues - }) - } - } catch (e) { - // eslint-disable-next-line no-console - console.log('Task History update error', e) - } - } - } - } - ) - - Task.associate = (models) => { - Task.belongsTo(models.Project) - Task.belongsTo(models.User, { foreignKey: 'userId' }) - Task.hasMany(models.History, { foreignKey: 'TaskId' }) - Task.hasMany(models.Order, { foreignKey: 'TaskId' }) - Task.hasMany(models.Assign, { foreignKey: 'TaskId' }) - Task.hasMany(models.Offer, { foreignKey: 'taskId' }) - Task.hasMany(models.Member, { foreignKey: 'taskId' }) - Task.belongsToMany(models.Label, { - foreignKey: 'taskId', - allowNull: false, - otherKey: 'labelId', - through: 'TaskLabels', - onUpdate: 'cascade', - onDelete: 'cascade', - hooks: true - }) - Task.hasMany(models.TaskSolution, { foreignKey: 'taskId' }) - Task.hasOne(models.Transfer, { foreignKey: 'taskId' }) - } - - return Task -} diff --git a/src/models/task.ts b/src/models/task.ts new file mode 100644 index 000000000..73462f9b7 --- /dev/null +++ b/src/models/task.ts @@ -0,0 +1,234 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface TaskAttributes { + id: number + private: boolean + not_listed: boolean + provider?: string | null + description?: string | null + type?: string | null + level?: string | null + status: string + deadline?: Date | null + url?: string | null + title?: string | null + value?: string | null + paid: boolean + notified: boolean + transfer_id?: string | null + assigned?: number | null + TransferId?: number | null + ProjectId?: number | null + userId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type TaskCreationAttributes = Optional< + TaskAttributes, + 'id' | 'private' | 'not_listed' | 'provider' | 'description' | 'type' | 'level' | 'status' | 'deadline' | 'url' | 'title' | 'value' | 'paid' | 'notified' | 'transfer_id' | 'assigned' | 'TransferId' | 'ProjectId' | 'userId' | 'createdAt' | 'updatedAt' +> + +export default class Task + extends Model + implements TaskAttributes +{ + public id!: number + public private!: boolean + public not_listed!: boolean + public provider!: string | null + public description!: string | null + public type!: string | null + public level!: string | null + public status!: string + public deadline!: Date | null + public url!: string | null + public title!: string | null + public value!: string | null + public paid!: boolean + public notified!: boolean + public transfer_id!: string | null + public assigned!: number | null + public TransferId!: number | null + public ProjectId!: number | null + public userId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Task { + Task.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + private: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + not_listed: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + provider: { + type: DataTypes.STRING, + allowNull: true + }, + description: { + type: DataTypes.STRING, + allowNull: true + }, + type: { + type: DataTypes.STRING, + allowNull: true + }, + level: { + type: DataTypes.STRING, + allowNull: true + }, + status: { + type: DataTypes.STRING, + defaultValue: 'open' + }, + deadline: { + type: DataTypes.DATE, + allowNull: true + }, + url: { + type: DataTypes.STRING, + allowNull: true + }, + title: { + type: DataTypes.STRING, + allowNull: true + }, + value: { + type: DataTypes.DECIMAL, + allowNull: true + }, + paid: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + notified: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + transfer_id: { + type: DataTypes.STRING, + allowNull: true + }, + assigned: { + type: DataTypes.INTEGER, + references: { + model: 'Assigns', + key: 'id' + }, + allowNull: true + }, + TransferId: { + type: DataTypes.INTEGER, + references: { + model: 'Transfers', + key: 'id' + }, + allowNull: true + }, + ProjectId: { + type: DataTypes.INTEGER, + references: { + model: 'Projects', + key: 'id' + }, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Tasks', + timestamps: true, + hooks: { + afterCreate: async (instance: Task, options: any) => { + try { + const changed = instance.changed() + await sequelize.models.History.create({ + TaskId: instance.id, + type: 'create', + fields: changed, + oldValues: Object.values(instance.previous()), + newValues: changed ? (changed as string[]).map((v: string) => (instance as any).dataValues[v]) : [] + }) + } catch (e) { + // eslint-disable-next-line no-console + console.log('Task History update error', e) + } + }, + afterUpdate: async (instance: Task, options: any) => { + try { + const changed = instance.changed() + const previous = Object.values(instance.previous()) + const newValues = changed ? (changed as string[]).map((v: string) => `${(instance as any).dataValues[v]}`) : [] + if ( + JSON.stringify(previous) !== JSON.stringify(newValues) && + JSON.stringify(changed) !== JSON.stringify(['id', 'updatedAt']) && + JSON.stringify(changed) !== JSON.stringify(['value', 'updatedAt']) && + previous[0] !== 'null' && + newValues[0] !== '0' + ) { + await sequelize.models.History.create({ + TaskId: instance.id, + type: 'update', + fields: changed, + oldValues: previous, + newValues: newValues + }) + } + } catch (e) { + // eslint-disable-next-line no-console + console.log('Task History update error', e) + } + } + } + } + ) + return Task + } + + static associate(models: any) { + models.Task.belongsTo(models.Project) + models.Task.belongsTo(models.User, { foreignKey: 'userId' }) + models.Task.hasMany(models.History, { foreignKey: 'TaskId' }) + models.Task.hasMany(models.Order, { foreignKey: 'TaskId' }) + models.Task.hasMany(models.Assign, { foreignKey: 'TaskId' }) + models.Task.hasMany(models.Offer, { foreignKey: 'taskId' }) + models.Task.hasMany(models.Member, { foreignKey: 'taskId' }) + models.Task.belongsToMany(models.Label, { + foreignKey: 'taskId', + allowNull: false, + otherKey: 'labelId', + through: 'TaskLabels', + onUpdate: 'cascade', + onDelete: 'cascade', + hooks: true + }) + models.Task.hasMany(models.TaskSolution, { foreignKey: 'taskId' }) + models.Task.hasOne(models.Transfer, { foreignKey: 'taskId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Task.initModel(sequelize) +} +module.exports.Task = Task +module.exports.default = Task diff --git a/src/models/taskSolution.js b/src/models/taskSolution.js deleted file mode 100644 index a6a8e8bd6..000000000 --- a/src/models/taskSolution.js +++ /dev/null @@ -1,40 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const TaskSolution = sequelize.define('TaskSolution', { - pullRequestURL: { - type: DataTypes.STRING, - allowNull: false - }, - isAuthorOfPR: { - allowNull: false, - defaultValue: false, - type: DataTypes.BOOLEAN - }, - isConnectedToGitHub: { - allowNull: false, - defaultValue: false, - type: DataTypes.BOOLEAN - }, - isPRMerged: { - allowNull: false, - defaultValue: false, - type: DataTypes.BOOLEAN - }, - isIssueClosed: { - allowNull: false, - defaultValue: false, - type: DataTypes.BOOLEAN - }, - hasIssueReference: { - allowNull: false, - defaultValue: false, - type: DataTypes.BOOLEAN - } - }) - - TaskSolution.associate = (models) => { - TaskSolution.belongsTo(models.Task, { foreignKey: 'taskId' }) - TaskSolution.belongsTo(models.User, { foreignKey: 'userId' }) - } - - return TaskSolution -} diff --git a/src/models/taskSolution.ts b/src/models/taskSolution.ts new file mode 100644 index 000000000..64b7830b5 --- /dev/null +++ b/src/models/taskSolution.ts @@ -0,0 +1,105 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface TaskSolutionAttributes { + id: number + pullRequestURL: string + isAuthorOfPR: boolean + isConnectedToGitHub: boolean + isPRMerged: boolean + isIssueClosed: boolean + hasIssueReference: boolean + taskId?: number | null + userId?: number | null + createdAt?: Date + updatedAt?: Date +} + +export type TaskSolutionCreationAttributes = Optional< + TaskSolutionAttributes, + 'id' | 'isAuthorOfPR' | 'isConnectedToGitHub' | 'isPRMerged' | 'isIssueClosed' | 'hasIssueReference' | 'taskId' | 'userId' | 'createdAt' | 'updatedAt' +> + +export default class TaskSolution + extends Model + implements TaskSolutionAttributes +{ + public id!: number + public pullRequestURL!: string + public isAuthorOfPR!: boolean + public isConnectedToGitHub!: boolean + public isPRMerged!: boolean + public isIssueClosed!: boolean + public hasIssueReference!: boolean + public taskId!: number | null + public userId!: number | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof TaskSolution { + TaskSolution.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + pullRequestURL: { + type: DataTypes.STRING, + allowNull: false + }, + isAuthorOfPR: { + allowNull: false, + defaultValue: false, + type: DataTypes.BOOLEAN + }, + isConnectedToGitHub: { + allowNull: false, + defaultValue: false, + type: DataTypes.BOOLEAN + }, + isPRMerged: { + allowNull: false, + defaultValue: false, + type: DataTypes.BOOLEAN + }, + isIssueClosed: { + allowNull: false, + defaultValue: false, + type: DataTypes.BOOLEAN + }, + hasIssueReference: { + allowNull: false, + defaultValue: false, + type: DataTypes.BOOLEAN + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'TaskSolutions', + timestamps: true + } + ) + return TaskSolution + } + + static associate(models: any) { + models.TaskSolution.belongsTo(models.Task, { foreignKey: 'taskId' }) + models.TaskSolution.belongsTo(models.User, { foreignKey: 'userId' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return TaskSolution.initModel(sequelize) +} +module.exports.TaskSolution = TaskSolution +module.exports.default = TaskSolution diff --git a/src/models/transfer.js b/src/models/transfer.js deleted file mode 100644 index cc33193b5..000000000 --- a/src/models/transfer.js +++ /dev/null @@ -1,56 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Transfer = sequelize.define( - 'Transfer', - { - status: { - type: DataTypes.STRING, - defaultValue: 'pending' - }, - value: DataTypes.DECIMAL, - transfer_id: DataTypes.STRING, - transfer_method: DataTypes.STRING, - paypal_payout_id: DataTypes.STRING, - paypal_transfer_amount: DataTypes.DECIMAL, - stripe_transfer_amount: DataTypes.DECIMAL, - taskId: { - type: DataTypes.INTEGER, - references: { - model: 'Tasks', - key: 'id' - }, - allowNull: false - }, - userId: { - type: DataTypes.INTEGER, - references: { - model: 'Users', - key: 'id' - }, - allowNull: false - }, - to: { - type: DataTypes.INTEGER, - references: { - model: 'Users', - key: 'id' - }, - allowNull: false - } - }, - {} - ) - - Transfer.associate = function (models) { - Transfer.belongsTo(models.Task, { - foreignKey: 'taskId' - }) - Transfer.belongsTo(models.User, { - foreignKey: 'userId', - as: 'User' - }) - - Transfer.belongsTo(models.User, { foreignKey: 'to', as: 'destination' }) - } - - return Transfer -} diff --git a/src/models/transfer.ts b/src/models/transfer.ts new file mode 100644 index 000000000..4a2093086 --- /dev/null +++ b/src/models/transfer.ts @@ -0,0 +1,141 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface TransferAttributes { + id: number + status: string + value?: string | null + transfer_id?: string | null + transfer_method?: string | null + paypal_payout_id?: string | null + paypal_transfer_amount?: string | null + stripe_transfer_amount?: string | null + taskId: number + userId: number + to: number + createdAt?: Date + updatedAt?: Date +} + +export type TransferCreationAttributes = Optional< + TransferAttributes, + 'id' | 'status' | 'value' | 'transfer_id' | 'transfer_method' | 'paypal_payout_id' | 'paypal_transfer_amount' | 'stripe_transfer_amount' | 'createdAt' | 'updatedAt' +> + +export default class Transfer + extends Model + implements TransferAttributes +{ + public id!: number + public status!: string + public value!: string | null + public transfer_id!: string | null + public transfer_method!: string | null + public paypal_payout_id!: string | null + public paypal_transfer_amount!: string | null + public stripe_transfer_amount!: string | null + public taskId!: number + public userId!: number + public to!: number + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Transfer { + Transfer.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + status: { + type: DataTypes.STRING, + defaultValue: 'pending' + }, + value: { + type: DataTypes.DECIMAL, + allowNull: true + }, + transfer_id: { + type: DataTypes.STRING, + allowNull: true + }, + transfer_method: { + type: DataTypes.STRING, + allowNull: true + }, + paypal_payout_id: { + type: DataTypes.STRING, + allowNull: true + }, + paypal_transfer_amount: { + type: DataTypes.DECIMAL, + allowNull: true + }, + stripe_transfer_amount: { + type: DataTypes.DECIMAL, + allowNull: true + }, + taskId: { + type: DataTypes.INTEGER, + references: { + model: 'Tasks', + key: 'id' + }, + allowNull: false + }, + userId: { + type: DataTypes.INTEGER, + references: { + model: 'Users', + key: 'id' + }, + allowNull: false + }, + to: { + type: DataTypes.INTEGER, + references: { + model: 'Users', + key: 'id' + }, + allowNull: false + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Transfers', + timestamps: true + } + ) + return Transfer + } + + static associate(models: any) { + models.Transfer.belongsTo(models.Task, { + foreignKey: 'taskId' + }) + models.Transfer.belongsTo(models.User, { + foreignKey: 'userId', + as: 'User' + }) + models.Transfer.belongsTo(models.User, { + foreignKey: 'to', + as: 'destination' + }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Transfer.initModel(sequelize) +} +module.exports.Transfer = Transfer +module.exports.default = Transfer diff --git a/src/models/type.js b/src/models/type.js deleted file mode 100644 index e3fdbb6c6..000000000 --- a/src/models/type.js +++ /dev/null @@ -1,13 +0,0 @@ -module.exports = (sequelize, DataTypes) => { - const Type = sequelize.define('Type', { - name: DataTypes.STRING, - label: DataTypes.STRING, - description: DataTypes.STRING - }) - - Type.associate = (models) => { - Type.belongsToMany(models.User, { through: 'User_Types' }) - } - - return Type -} diff --git a/src/models/type.ts b/src/models/type.ts new file mode 100644 index 000000000..df028b6a9 --- /dev/null +++ b/src/models/type.ts @@ -0,0 +1,77 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export interface TypeAttributes { + id: number + name?: string | null + label?: string | null + description?: string | null + createdAt?: Date + updatedAt?: Date +} + +export type TypeCreationAttributes = Optional< + TypeAttributes, + 'id' | 'name' | 'label' | 'description' | 'createdAt' | 'updatedAt' +> + +export default class Type + extends Model + implements TypeAttributes +{ + public id!: number + public name!: string | null + public label!: string | null + public description!: string | null + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Type { + Type.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + label: { + type: DataTypes.STRING, + allowNull: true + }, + description: { + type: DataTypes.STRING, + allowNull: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Types', + timestamps: true + } + ) + return Type + } + + static associate(models: any) { + models.Type.belongsToMany(models.User, { through: 'User_Types' }) + } +} + +module.exports = (sequelize: Sequelize) => { + return Type.initModel(sequelize) +} +module.exports.Type = Type +module.exports.default = Type diff --git a/src/models/user.js b/src/models/user.js deleted file mode 100644 index d17d11938..000000000 --- a/src/models/user.js +++ /dev/null @@ -1,72 +0,0 @@ -const bcrypt = require('bcrypt') -const crypto = require('crypto') - -module.exports = (sequelize, DataTypes) => { - const User = sequelize.define('User', { - login_strategy: { - type: DataTypes.STRING, - defaultValue: 'local' - }, - provider: DataTypes.STRING, - provider_id: DataTypes.STRING, - provider_username: DataTypes.STRING, - provider_email: DataTypes.STRING, - email: DataTypes.STRING, - email_verified: DataTypes.BOOLEAN, - pending_email_change: DataTypes.STRING, - email_change_token: DataTypes.STRING, - email_change_token_expires_at: DataTypes.DATE, - email_change_requested_at: DataTypes.DATE, - email_change_attempts: DataTypes.INTEGER, - password: DataTypes.STRING, - name: DataTypes.STRING, - username: DataTypes.STRING, - website: DataTypes.STRING, - repos: DataTypes.STRING, - language: DataTypes.STRING, - country: DataTypes.STRING, - profile_url: DataTypes.STRING, - picture_url: DataTypes.STRING, - customer_id: DataTypes.STRING, - account_id: DataTypes.STRING, - paypal_id: DataTypes.STRING, - os: DataTypes.STRING, - skills: DataTypes.STRING, - languages: DataTypes.STRING, - recover_password_token: DataTypes.STRING, - activation_token: DataTypes.STRING, - receiveNotifications: { - type: DataTypes.BOOLEAN, - defaultValue: true - }, - openForJobs: { - type: DataTypes.BOOLEAN, - defaultValue: false - }, - active: { - type: DataTypes.BOOLEAN, - defaultValue: true - } - }) - - User.associate = (models) => { - User.hasMany(models.Organization) - User.hasMany(models.Payout, { foreignKey: 'userId' }) - User.belongsToMany(models.Type, { through: 'User_Types' }) - } - - User.generateHash = (password) => { - /* eslint-disable no-sync */ - return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null) - } - - User.generateToken = () => { - return crypto.randomBytes(64).toString('hex') - } - - User.prototype.verifyPassword = (password, databasePassword) => { - return bcrypt.compareSync(password, databasePassword) - } - - return User -} diff --git a/src/models/user.ts b/src/models/user.ts new file mode 100644 index 000000000..623df7db7 --- /dev/null +++ b/src/models/user.ts @@ -0,0 +1,268 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' +import * as bcrypt from 'bcrypt' +import * as crypto from 'crypto' + +export interface UserAttributes { + id: number + login_strategy: string + provider?: string | null + provider_id?: string | null + provider_username?: string | null + provider_email?: string | null + email?: string | null + email_verified?: boolean | null + pending_email_change?: string | null + email_change_token?: string | null + email_change_token_expires_at?: Date | null + email_change_requested_at?: Date | null + email_change_attempts?: number | null + password?: string | null + name?: string | null + username?: string | null + website?: string | null + repos?: string | null + language?: string | null + country?: string | null + profile_url?: string | null + picture_url?: string | null + customer_id?: string | null + account_id?: string | null + paypal_id?: string | null + os?: string | null + skills?: string | null + languages?: string | null + recover_password_token?: string | null + activation_token?: string | null + receiveNotifications: boolean + openForJobs: boolean + active: boolean + createdAt?: Date + updatedAt?: Date +} + +export type UserCreationAttributes = Optional< + UserAttributes, + 'id' | 'login_strategy' | 'provider' | 'provider_id' | 'provider_username' | 'provider_email' | 'email' | 'email_verified' | 'pending_email_change' | 'email_change_token' | 'email_change_token_expires_at' | 'email_change_requested_at' | 'email_change_attempts' | 'password' | 'name' | 'username' | 'website' | 'repos' | 'language' | 'country' | 'profile_url' | 'picture_url' | 'customer_id' | 'account_id' | 'paypal_id' | 'os' | 'skills' | 'languages' | 'recover_password_token' | 'activation_token' | 'receiveNotifications' | 'openForJobs' | 'active' | 'createdAt' | 'updatedAt' +> + +export default class User + extends Model + implements UserAttributes +{ + public id!: number + public login_strategy!: string + public provider!: string | null + public provider_id!: string | null + public provider_username!: string | null + public provider_email!: string | null + public email!: string | null + public email_verified!: boolean | null + public pending_email_change!: string | null + public email_change_token!: string | null + public email_change_token_expires_at!: Date | null + public email_change_requested_at!: Date | null + public email_change_attempts!: number | null + public password!: string | null + public name!: string | null + public username!: string | null + public website!: string | null + public repos!: string | null + public language!: string | null + public country!: string | null + public profile_url!: string | null + public picture_url!: string | null + public customer_id!: string | null + public account_id!: string | null + public paypal_id!: string | null + public os!: string | null + public skills!: string | null + public languages!: string | null + public recover_password_token!: string | null + public activation_token!: string | null + public receiveNotifications!: boolean + public openForJobs!: boolean + public active!: boolean + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof User { + User.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + login_strategy: { + type: DataTypes.STRING, + defaultValue: 'local' + }, + provider: { + type: DataTypes.STRING, + allowNull: true + }, + provider_id: { + type: DataTypes.STRING, + allowNull: true + }, + provider_username: { + type: DataTypes.STRING, + allowNull: true + }, + provider_email: { + type: DataTypes.STRING, + allowNull: true + }, + email: { + type: DataTypes.STRING, + allowNull: true + }, + email_verified: { + type: DataTypes.BOOLEAN, + allowNull: true + }, + pending_email_change: { + type: DataTypes.STRING, + allowNull: true + }, + email_change_token: { + type: DataTypes.STRING, + allowNull: true + }, + email_change_token_expires_at: { + type: DataTypes.DATE, + allowNull: true + }, + email_change_requested_at: { + type: DataTypes.DATE, + allowNull: true + }, + email_change_attempts: { + type: DataTypes.INTEGER, + allowNull: true + }, + password: { + type: DataTypes.STRING, + allowNull: true + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + username: { + type: DataTypes.STRING, + allowNull: true + }, + website: { + type: DataTypes.STRING, + allowNull: true + }, + repos: { + type: DataTypes.STRING, + allowNull: true + }, + language: { + type: DataTypes.STRING, + allowNull: true + }, + country: { + type: DataTypes.STRING, + allowNull: true + }, + profile_url: { + type: DataTypes.STRING, + allowNull: true + }, + picture_url: { + type: DataTypes.STRING, + allowNull: true + }, + customer_id: { + type: DataTypes.STRING, + allowNull: true + }, + account_id: { + type: DataTypes.STRING, + allowNull: true + }, + paypal_id: { + type: DataTypes.STRING, + allowNull: true + }, + os: { + type: DataTypes.STRING, + allowNull: true + }, + skills: { + type: DataTypes.STRING, + allowNull: true + }, + languages: { + type: DataTypes.STRING, + allowNull: true + }, + recover_password_token: { + type: DataTypes.STRING, + allowNull: true + }, + activation_token: { + type: DataTypes.STRING, + allowNull: true + }, + receiveNotifications: { + type: DataTypes.BOOLEAN, + defaultValue: true + }, + openForJobs: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + active: { + type: DataTypes.BOOLEAN, + defaultValue: true + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Users', + timestamps: true + } + ) + return User + } + + static associate(models: any) { + models.User.hasMany(models.Organization) + models.User.hasMany(models.Payout, { foreignKey: 'userId' }) + models.User.belongsToMany(models.Type, { through: 'User_Types' }) + } + + static generateHash(password: string): string { + /* eslint-disable no-sync */ + return bcrypt.hashSync(password, bcrypt.genSaltSync(8)) + } + + static generateToken(): string { + return crypto.randomBytes(64).toString('hex') + } + + verifyPassword(password: string, databasePassword: string): boolean { + return bcrypt.compareSync(password, databasePassword) + } +} + +module.exports = (sequelize: Sequelize) => { + return User.initModel(sequelize) +} +module.exports.User = User +module.exports.default = User diff --git a/src/models/wallet.js b/src/models/wallet.js deleted file mode 100644 index 63c1fea74..000000000 --- a/src/models/wallet.js +++ /dev/null @@ -1,86 +0,0 @@ -const Decimal = require('decimal.js') - -module.exports = (sequelize, DataTypes) => { - const Wallet = sequelize.define('Wallet', { - userId: { - type: DataTypes.INTEGER, - allowNull: false - }, - name: { - type: DataTypes.STRING - }, - balance: { - type: DataTypes.DECIMAL, - allowNull: false - } - }) - - Wallet.associate = function (models) { - Wallet.hasMany(models.WalletOrder, { - foreignKey: 'walletId' - }) - Wallet.belongsTo(models.User, { - foreignKey: 'userId' - }) - } - - Wallet.prototype.addBalance = async function () { - const orders = await sequelize.models.WalletOrder.findAll({ - where: { - walletId: this.id, - status: 'paid' - } - }) - const balance = orders.reduce((acc, order) => { - return acc.plus(order.amount) - }, new Decimal(0)) - return balance - } - - Wallet.prototype.spendBalance = async function () { - const orders = await sequelize.models.Order.findAll({ - where: { - provider: 'wallet', - source_type: 'wallet-funds', - source_id: `${this.id}`, - status: 'succeeded' - } - }) - const balance = orders.reduce((acc, order) => { - const fee = order.amount >= 5000 ? 1 : 1.08 - return acc.plus(order.amount * fee) - }, new Decimal(0)) - return balance - } - - Wallet.prototype.totalBalance = async function () { - const totalAddedBalance = await this.addBalance() - const addedBalance = new Decimal(totalAddedBalance) - return addedBalance.minus(await this.spendBalance()) - } - - Wallet.addHook('afterFind', async (wallet, options) => { - if (!wallet) return - - if (Array.isArray(wallet)) { - // Handle findAll case - for (const singleWallet of wallet) { - await updateWalletBalance(singleWallet, options) - } - } else { - // Handle findByPk or findOne case - await updateWalletBalance(wallet, options) - } - }) - - // Helper function to update the balance of a wallet - async function updateWalletBalance(wallet, options) { - const totalBalance = await wallet.totalBalance() // Calculate balance using your methods - wallet.balance = totalBalance.toFixed(2) // Update the balance field in memory - await wallet.save({ - transaction: options.transaction - }) // Persist the updated balance to the database (optional) - } - - return Wallet -} diff --git a/src/models/wallet.ts b/src/models/wallet.ts new file mode 100644 index 000000000..78c6e0902 --- /dev/null +++ b/src/models/wallet.ts @@ -0,0 +1,149 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' +import Decimal from 'decimal.js' + +export interface WalletAttributes { + id: number + userId: number + name?: string | null + balance: string + createdAt?: Date + updatedAt?: Date +} + +export type WalletCreationAttributes = Optional< + WalletAttributes, + 'id' | 'name' | 'createdAt' | 'updatedAt' +> + +export default class Wallet + extends Model + implements WalletAttributes +{ + public id!: number + public userId!: number + public name!: string | null + public balance!: string + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof Wallet { + Wallet.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + userId: { + type: DataTypes.INTEGER, + allowNull: false + }, + name: { + type: DataTypes.STRING, + allowNull: true + }, + balance: { + type: DataTypes.DECIMAL, + allowNull: false + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'Wallets', + timestamps: true, + hooks: { + afterFind: async (wallet: Wallet | Wallet[] | null, options: any) => { + if (!wallet) return + + if (Array.isArray(wallet)) { + // Handle findAll case + for (const singleWallet of wallet) { + await updateWalletBalance(singleWallet, options) + } + } else { + // Handle findByPk or findOne case + await updateWalletBalance(wallet, options) + } + } + } + } + ) + + // Helper function to update the balance of a wallet + async function updateWalletBalance(wallet: Wallet, options: any) { + const totalBalance = await wallet.totalBalance() // Calculate balance using your methods + wallet.balance = totalBalance.toFixed(2) // Update the balance field in memory + await wallet.save({ + transaction: options.transaction + }) // Persist the updated balance to the database (optional) + } + + return Wallet + } + + static associate(models: any) { + models.Wallet.hasMany(models.WalletOrder, { + foreignKey: 'walletId' + }) + models.Wallet.belongsTo(models.User, { + foreignKey: 'userId' + }) + } + + async addBalance(): Promise { + const sequelize = this.sequelize + if (!sequelize) throw new Error('Sequelize instance not found') + + const orders = await sequelize.models.WalletOrder.findAll({ + where: { + walletId: this.id, + status: 'paid' + } + }) + const balance = orders.reduce((acc: Decimal, order: any) => { + return acc.plus(order.amount) + }, new Decimal(0)) + return balance + } + + async spendBalance(): Promise { + const sequelize = this.sequelize + if (!sequelize) throw new Error('Sequelize instance not found') + + const orders = await sequelize.models.Order.findAll({ + where: { + provider: 'wallet', + source_type: 'wallet-funds', + source_id: `${this.id}`, + status: 'succeeded' + } + }) + const balance = orders.reduce((acc: Decimal, order: any) => { + const fee = order.amount >= 5000 ? 1 : 1.08 + return acc.plus(order.amount * fee) + }, new Decimal(0)) + return balance + } + + async totalBalance(): Promise { + const totalAddedBalance = await this.addBalance() + const addedBalance = new Decimal(totalAddedBalance) + return addedBalance.minus(await this.spendBalance()) + } +} + +module.exports = (sequelize: Sequelize) => { + return Wallet.initModel(sequelize) +} +module.exports.Wallet = Wallet +module.exports.default = Wallet diff --git a/src/models/walletOrder.js b/src/models/walletOrder.js deleted file mode 100644 index f33578f1d..000000000 --- a/src/models/walletOrder.js +++ /dev/null @@ -1,55 +0,0 @@ -const Decimal = require('decimal.js') - -module.exports = (sequelize, DataTypes) => { - const WalletOrder = sequelize.define('WalletOrder', { - walletId: { - type: DataTypes.INTEGER, - allowNull: false - }, - source_id: { - type: DataTypes.STRING - }, - currency: { - type: DataTypes.STRING - }, - amount: { - type: DataTypes.DECIMAL, - allowNull: false - }, - description: { - type: DataTypes.STRING - }, - source_type: { - type: DataTypes.STRING - }, - source: { - type: DataTypes.STRING, - unique: true - }, - capture: { - type: DataTypes.BOOLEAN - }, - ordered_in: { - type: DataTypes.DATE - }, - destination: { - type: DataTypes.STRING - }, - paid: { - type: DataTypes.BOOLEAN - }, - status: { - type: DataTypes.ENUM, - values: ['pending', 'draft', 'open', 'paid', 'failed', 'uncollectible', 'void', 'refunded'], - defaultValue: 'pending' - } - }) - - WalletOrder.associate = function (models) { - WalletOrder.belongsTo(models.Wallet, { - foreignKey: 'walletId' - }) - } - - return WalletOrder -} diff --git a/src/models/walletOrder.ts b/src/models/walletOrder.ts new file mode 100644 index 000000000..a8e6dee26 --- /dev/null +++ b/src/models/walletOrder.ts @@ -0,0 +1,136 @@ +import { Model, DataTypes, Optional, Sequelize } from 'sequelize' + +export type WalletOrderStatus = 'pending' | 'draft' | 'open' | 'paid' | 'failed' | 'uncollectible' | 'void' | 'refunded' + +export interface WalletOrderAttributes { + id: number + walletId: number + source_id?: string | null + currency?: string | null + amount: string + description?: string | null + source_type?: string | null + source?: string | null + capture?: boolean | null + ordered_in?: Date | null + destination?: string | null + paid?: boolean | null + status: WalletOrderStatus + createdAt?: Date + updatedAt?: Date +} + +export type WalletOrderCreationAttributes = Optional< + WalletOrderAttributes, + 'id' | 'source_id' | 'currency' | 'description' | 'source_type' | 'source' | 'capture' | 'ordered_in' | 'destination' | 'paid' | 'status' | 'createdAt' | 'updatedAt' +> + +export default class WalletOrder + extends Model + implements WalletOrderAttributes +{ + public id!: number + public walletId!: number + public source_id!: string | null + public currency!: string | null + public amount!: string + public description!: string | null + public source_type!: string | null + public source!: string | null + public capture!: boolean | null + public ordered_in!: Date | null + public destination!: string | null + public paid!: boolean | null + public status!: WalletOrderStatus + public createdAt!: Date + public updatedAt!: Date + + static initModel(sequelize: Sequelize): typeof WalletOrder { + WalletOrder.init( + { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + walletId: { + type: DataTypes.INTEGER, + allowNull: false + }, + source_id: { + type: DataTypes.STRING, + allowNull: true + }, + currency: { + type: DataTypes.STRING, + allowNull: true + }, + amount: { + type: DataTypes.DECIMAL, + allowNull: false + }, + description: { + type: DataTypes.STRING, + allowNull: true + }, + source_type: { + type: DataTypes.STRING, + allowNull: true + }, + source: { + type: DataTypes.STRING, + unique: true, + allowNull: true + }, + capture: { + type: DataTypes.BOOLEAN, + allowNull: true + }, + ordered_in: { + type: DataTypes.DATE, + allowNull: true + }, + destination: { + type: DataTypes.STRING, + allowNull: true + }, + paid: { + type: DataTypes.BOOLEAN, + allowNull: true + }, + status: { + type: DataTypes.ENUM('pending', 'draft', 'open', 'paid', 'failed', 'uncollectible', 'void', 'refunded'), + defaultValue: 'pending' + }, + createdAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + }, + updatedAt: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW + } + }, + { + sequelize, + tableName: 'WalletOrders', + timestamps: true + } + ) + return WalletOrder + } + + static associate(models: any) { + models.WalletOrder.belongsTo(models.Wallet, { + foreignKey: 'walletId' + }) + } +} + +module.exports = (sequelize: Sequelize) => { + return WalletOrder.initModel(sequelize) +} +module.exports.WalletOrder = WalletOrder +module.exports.default = WalletOrder