Skip to content

Commit

Permalink
Changed accounts to use discriminators for different types
Browse files Browse the repository at this point in the history
- This works like unions in C (polymorphism)
  • Loading branch information
Minipoloalex committed Jun 3, 2024
1 parent 82886d0 commit 05f9971
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 60 deletions.
6 changes: 4 additions & 2 deletions src/api/middleware/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import OfferService from "../../services/offer.js";
import ValidationReasons from "./validators/validationReasons.js";
import { or, storeInLocals } from "./utils.js";
import { verifyAndDecodeToken } from "../../lib/token.js";
import CompanyAccount from "../../models/CompanyAccount.js";
import AdminAccount from "../../models/AdminAccount.js";

// Middleware to require login in an endpoint
export const authRequired = (req, res, next) => {
Expand All @@ -27,12 +29,12 @@ export const isGod = (req, res, next) => {
};

export const isCompany = (req, res, next) => {
if (req?.user?.company) return next();
if (req.user instanceof CompanyAccount) return next();
else return next(new APIError(HTTPStatus.UNAUTHORIZED, ErrorTypes.FORBIDDEN, ValidationReasons.MUST_BE_COMPANY));
};

export const isAdmin = (req, res, next) => {
if (!req.user?.isAdmin) {
if (!(req.user instanceof AdminAccount)) {
return next(new APIError(HTTPStatus.UNAUTHORIZED, ErrorTypes.FORBIDDEN, ValidationReasons.MUST_BE_ADMIN));
}

Expand Down
42 changes: 25 additions & 17 deletions src/api/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { authRequired, isGod, validToken } from "../middleware/auth.js";
import * as validators from "../middleware/validators/auth.js";
import AccountService from "../../services/account.js";
import Company from "../../models/Company.js";
import CompanyAccount from "../../models/CompanyAccount.js";
import AdminAccount from "../../models/AdminAccount.js";

const router = Router();

Expand All @@ -14,24 +16,30 @@ export default (app) => {

// Get logged in user info
router.get("/me", authRequired, async (req, res) => {
const { email, isAdmin, company: companyId } = req.user;

let company = undefined;

try {
if (companyId)
company = await Company.findById(companyId);
} catch (e) {
console.error(`Could not find the respective company of user ${req.user._id}, with id ${companyId}`, e);
const email = req.user.email;

if (req.user instanceof CompanyAccount) {
const companyId = req.user.company;
try {
const company = await Company.findById(companyId);
return res.status(HTTPStatus.OK).json({
data: {
email, isAdmin: false, company
}
});
} catch (e) {
console.error(`Could not find the respective company of user ${req.user._id}, with id ${companyId}`, e);
}
} else if (req.user instanceof AdminAccount) {
return res.status(HTTPStatus.OK).json({
data: {
email, isAdmin: true, company: null
}
});
} else {
console.error(`Unknown user type: ${req.user}`);
}

return res.status(HTTPStatus.OK).json({
data: {
email,
isAdmin,
company
},
});
return res.status(HTTPStatus.INTERNAL_SERVER_ERROR).json({});
});

// Login endpoint
Expand Down
4 changes: 2 additions & 2 deletions src/loaders/mongoose.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import mongoose from "mongoose";
import config from "../config/env.js";
import Account from "../models/Account.js";
import AdminAccount from "../models/AdminAccount.js";
import hash from "../lib/passwordHashing.js";

export default async () => {
Expand Down Expand Up @@ -40,10 +41,9 @@ const createDefaultAdmin = async () => {
return;
}

await Account.create({
await AdminAccount.create({
email: config.admin_email,
password: await hash(config.admin_password),
isAdmin: true,
});

console.info("Created default admin!");
Expand Down
27 changes: 3 additions & 24 deletions src/models/Account.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import mongoose from "mongoose";
import bcrypt from "bcrypt";

const { Schema } = mongoose;

const AccountSchema = new Schema({
Expand All @@ -11,30 +12,8 @@ const AccountSchema = new Schema({
required: true,
},
password: { type: String, required: true },
isAdmin: {
type: Boolean,
default: false,
validate: {
validator: function(isAdmin) {
return isAdmin !== !!this.company;
},
message: "A user cannot be an admin and a company representative",
},
},
company: {
type: Schema.Types.ObjectId,
ref: "Company",
required: function() {
return !this.isAdmin;
},
validate: {
validator: function(company) {
return !!company !== this.isAdmin;
},
message: "A user cannot be a company representative and an admin",

},
},
}, {
discriminatorKey: "accountType",
});

AccountSchema.methods.validatePassword = async function(password) {
Expand Down
12 changes: 12 additions & 0 deletions src/models/AdminAccount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import mongoose from "mongoose";

import Account from "./Account.js";

const { Schema } = mongoose;


const AdminAccountSchema = new Schema({});

const AdminAccount = Account.discriminator("AdminAccount", AdminAccountSchema);

export default AdminAccount;
17 changes: 17 additions & 0 deletions src/models/CompanyAccount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import mongoose from "mongoose";

import Account from "./Account.js";

const { Schema } = mongoose;

const CompanyAccountSchema = new Schema({
company: {
type: Schema.Types.ObjectId,
ref: "Company",
required: true,
},
});

const CompanyAccount = Account.discriminator("CompanyAccount", CompanyAccountSchema);

export default CompanyAccount;
23 changes: 12 additions & 11 deletions src/services/account.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import Account from "../models/Account.js";
import AdminAccount from "../models/AdminAccount.js";
import CompanyAccount from "../models/CompanyAccount.js";
import hash from "../lib/passwordHashing.js";
import Company from "../models/Company.js";
import { RECOVERY_LINK_EXPIRATION } from "../models/constants/Account.js";
Expand All @@ -14,30 +16,28 @@ class AccountService {
}

async registerAdmin(email, password) {
const account = await Account.create({
const adminAccount = await AdminAccount.create({
email,
password: await hash(password),
isAdmin: true,
password: await hash(password)
});

return {
email: account.email,
email: adminAccount.email,
};
}

async registerCompany(email, password, companyName) {

const company = await Company.create({ name: companyName });

const account = await Account.create({
const companyAccount = await CompanyAccount.create({
email,
password,
company,
company
});

return {
email: account.email,
companyName: account.company.name,
email: companyAccount.email,
companyName: companyAccount.company.name,
};
}

Expand Down Expand Up @@ -69,8 +69,9 @@ class AccountService {

async findAndDeleteByCompanyId(company) {
try {
const account = await Account.findOne({ company });
await Account.findByIdAndRemove(account._id);
const account = CompanyAccount.findOne({ company });
await CompanyAccount.findByIdAndRemove(account._id);

return account;
} catch (err) {
console.error(err);
Expand Down
4 changes: 2 additions & 2 deletions src/services/company.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
COMPANY_DELETED_NOTIFICATION,
} from "../email-templates/companyManagement.js";
import EmailService from "../lib/emailService.js";
import Account from "../models/Account.js";
import CompanyAccount from "../models/CompanyAccount.js";
import Company from "../models/Company.js";
class CompanyService {
getOffersInTimePeriod(owner, publishDate, publishEndDate, OfferModel) {
Expand Down Expand Up @@ -120,7 +120,7 @@ class CompanyService {
async _sendCompanyNotification(companyId, notification) {
try {
const company = await Company.findById(companyId);
const companyAccount = await Account.findOne({
const companyAccount = await CompanyAccount.findOne({
company
});
await EmailService.sendMail({
Expand Down
4 changes: 2 additions & 2 deletions src/services/offer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import mongoose from "mongoose";
import Company from "../models/Company.js";
import Offer from "../models/Offer.js";
import Account from "../models/Account.js";
import CompanyAccount from "../models/CompanyAccount.js";
import EmailService from "../lib/emailService.js";
import { OFFER_DISABLED_NOTIFICATION } from "../email-templates/companyOfferDisabled.js";
import OfferConstants from "../models/constants/Offer.js";
Expand Down Expand Up @@ -483,7 +483,7 @@ class OfferService {
const offer = await Offer.findById(offerId);
if (!offer) return; // validation of offerId should be done before with an error

const companyAccount = await Account.findOne({
const companyAccount = await CompanyAccount.findOne({
company: await Company.findOne({ _id: offer.owner })
});

Expand Down

0 comments on commit 05f9971

Please sign in to comment.