diff --git a/README.md b/README.md
index 8dd71a2..b077e4d 100644
--- a/README.md
+++ b/README.md
@@ -103,7 +103,8 @@
Takes **restaurantId** query and returns a specific restaurant **JSON** if found. Else returns **400** if restaurantId is invalid, or **404** if specified restaurantId is not found.
- #### **POST**
Takes a **restaurant** document, and JWT **token (header)**, tries to create new restaurant in a database, and also add it to user restaurants list. Returns **201** on success. Else returns **401** on invalid token, and **400** on general error while adding restaurant.
- - #### **PUT** - empty!
+ - #### **PUT**
+ Takes a **restaurantId** and updates it with a supplied document.
@@ -179,6 +180,14 @@
+* ### **/search/location**
+
+ - #### **GET**
+
+ Takes a **lon, lat, and radius** query parameters and returns an **array** of restaurants in a specified radius from supplied location.
+
+
+
## **3. Important functions**
diff --git a/models/restaurant.js b/models/restaurant.js
index 9bdd6c9..f21c899 100644
--- a/models/restaurant.js
+++ b/models/restaurant.js
@@ -30,7 +30,6 @@ const restaurantSchema = mongoose.Schema({
},
imgUrl: {
type: String,
- required: true,
},
workingHours: {
type: String,
@@ -57,8 +56,8 @@ const restaurantSchema = mongoose.Schema({
phone: Number,
hidden: Boolean,
subscriptionActive: Boolean,
- subscriptionStarted: String,
- subscriptionDue: String,
+ subscriptionStarted: Date,
+ subscriptionDue: Date,
dishes: [mongoose.Types.ObjectId],
});
diff --git a/models/users.js b/models/users.js
index 2ea9179..07f72b2 100644
--- a/models/users.js
+++ b/models/users.js
@@ -13,23 +13,28 @@ const userSchema = mongoose.Schema({
firstname: {
type: String,
required: true,
+ maxlength: 64,
},
lastname: {
type: String,
required: true,
+ maxlength: 64,
},
billing: {
NIP: {
type: String,
required: true,
+ maxlength: 64,
},
adress: {
type: String,
required: true,
+ maxlength: 128,
},
companyName: {
type: String,
required: true,
+ maxlength: 64,
},
},
restaurants: [mongoose.Types.ObjectId],
diff --git a/package-lock.json b/package-lock.json
index 0adc379..635e026 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1889,11 +1889,6 @@
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
"dev": true
},
- "agile_crm": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/agile_crm/-/agile_crm-1.2.5.tgz",
- "integrity": "sha1-gj+s18LUpzesJ2viFc9t6wwylVg="
- },
"ajv": {
"version": "6.12.4",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
diff --git a/package.json b/package.json
index f6bff4f..b799091 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,6 @@
"license": "ISC",
"dependencies": {
"@azure/storage-blob": "^12.2.0-preview.1",
- "agile_crm": "^1.2.5",
"bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"cors": "^2.8.5",
diff --git a/routes/routeRestaurant.js b/routes/routeRestaurant.js
index 9c33d86..24e9c95 100644
--- a/routes/routeRestaurant.js
+++ b/routes/routeRestaurant.js
@@ -35,7 +35,7 @@ router.post("/", async (req, res) => {
try {
const token = req.headers["x-auth-token"];
const user = validateUserToken(token);
- const restaurant = createRestaurant(req.body);
+ const restaurant = await createRestaurant(req.body);
await restaurant.save();
await addRestaurantToUser(user, restaurant);
res.sendStatus(201);
@@ -44,6 +44,21 @@ router.post("/", async (req, res) => {
}
});
+// UPDATE RESTAURANT
+
+router.put("/", async (req, res) => {
+ try {
+ const token = req.headers["x-auth-token"];
+ const user = validateUserToken(token);
+ const oldRestaurant = await fetchRestaurant(req.body.restaurantId);
+ const newRestaurant = await createRestaurant(req.body, oldRestaurant);
+ await Restaurant.replaceOne({ _id: req.body.restaurantId }, newRestaurant);
+ res.send("Dane zostały zaktualizowane.");
+ } catch (error) {
+ handleError(error, res);
+ }
+});
+
// GET ALL DISHES FROM A RESTAURANT ID
router.get("/dishes", async (req, res) => {
diff --git a/routes/routeSearch.js b/routes/routeSearch.js
index 912aa9c..906a99d 100644
--- a/routes/routeSearch.js
+++ b/routes/routeSearch.js
@@ -1,8 +1,7 @@
import express from "express";
-import * as services from "../services/services.js";
import Restaurant from "../models/restaurant.js";
import sanitizer from "string-sanitizer";
-import restaurant from "../models/restaurant.js";
+import { handleError } from "../services/services.js";
var router = express.Router();
@@ -18,9 +17,10 @@ router.get("/", (req, res) => {
$and: [
{ $or: [{ city: { $regex: regex } }, { name: { $regex: regex } }] },
{ hidden: false },
+ { subscriptionActive: true },
],
},
- "_id name city imgUrl workingHours description tags phone hidden",
+ "_id name city imgUrl workingHours description tags location links",
(err, results) => {
if (err) {
res.sendStatus(500);
@@ -36,6 +36,24 @@ router.get("/", (req, res) => {
}
});
+// SEARCH RESTAURANTS BY LOCATION
+
+router.get("/location", async (req, res) => {
+ try {
+ const location = {
+ coordinates: [req.query.lon, req.query.lat],
+ type: "Point",
+ };
+ const radius = parseInt(req.query.radius) * 1000;
+ const results = await Restaurant.find({
+ location: { $near: { $maxDistance: radius, $geometry: location } },
+ });
+ res.send(results);
+ } catch (error) {
+ handleError(error, res);
+ }
+});
+
// AUTOCOMPLETE
router.get("/autocomplete/", (req, res) => {
diff --git a/routes/routeTest.js b/routes/routeTest.js
index a882860..7fd27f0 100644
--- a/routes/routeTest.js
+++ b/routes/routeTest.js
@@ -1,14 +1,16 @@
import express from "express";
import * as services from "../services/services.js";
+import * as databaseServices from "../services/databaseServices.js";
var router = express.Router();
router.post("/", async (req, res) => {
try {
- const decodedToken = services.validateUserToken(
- req.headers["x-auth-token"]
+ const newDate = await databaseServices.renewSubscription(
+ req.body.restaurantId,
+ 1
);
- res.send(decodedToken);
+ res.send(`Subskrypcja przedłużona do: ${newDate}`);
} catch (error) {
services.handleError(error, res);
}
diff --git a/routes/routeUser.js b/routes/routeUser.js
index b64cfbc..35fa24a 100644
--- a/routes/routeUser.js
+++ b/routes/routeUser.js
@@ -1,10 +1,6 @@
import express from "express";
import { changeUserPass, fetchUser } from "../services/databaseServices.js";
-import {
- composeNewContact,
- createUser,
- prepareSafeUser,
-} from "../services/dataPrepServices.js";
+import { createUser, prepareSafeUser } from "../services/dataPrepServices.js";
import {
newError,
handleError,
@@ -14,13 +10,9 @@ import {
validateUserToken,
hashPass,
} from "../services/services.js";
-import * as config from "../config/index.js";
-import AgileCRMManager from "agile_crm";
import { resetPassword } from "../services/mailServices.js";
-const { CRM_USER, CRM_EMAIL, CRM_KEY } = config;
var router = express.Router();
-var agileAPI = new AgileCRMManager(CRM_USER, CRM_KEY, CRM_EMAIL);
// LOGIN
router.post("/login", async (req, res) => {
@@ -43,9 +35,9 @@ router.post("/register", async (req, res) => {
try {
await checkEmailTaken(req.body.email);
const user = await createUser(req);
- await user.save();
- const contact = composeNewContact(user);
- agileAPI.contactAPI.add(contact, null, null);
+ await user.save().catch((e) => {
+ throw newError("Niewłaściwe dane.", 500);
+ });
res.sendStatus(201);
} catch (e) {
handleError(e, res);
diff --git a/services/dataPrepServices.js b/services/dataPrepServices.js
index b7e658a..ff67941 100644
--- a/services/dataPrepServices.js
+++ b/services/dataPrepServices.js
@@ -5,52 +5,6 @@ import Dish from "../models/dish.js";
import User from "../models/users.js";
import Restaurant from "../models/restaurant.js";
-export function composeNewContact(request) {
- const contact = {
- lead_score: "100",
- tags: ["newUser"],
- properties: [
- {
- type: "SYSTEM",
- name: "first_name",
- value: request.firstname,
- },
- {
- type: "SYSTEM",
- name: "last_name",
- value: request.lastname,
- },
- {
- type: "SYSTEM",
- name: "email",
- subtype: "work",
- value: request.email,
- },
- {
- type: "CUSTOM",
- name: "UserID",
- value: request._id,
- },
- {
- type: "CUSTOM",
- name: "NIP",
- value: request.NIP,
- },
- {
- type: "CUSTOM",
- name: "CompanyName",
- value: request.companyName,
- },
- {
- type: "CUSTOM",
- name: "CompanyAdress",
- value: request.adress,
- },
- ],
- };
- return contact;
-}
-
export async function createUser(request) {
const password = await hashPass(request.body.password);
const user = new User({
@@ -68,25 +22,68 @@ export async function createUser(request) {
return user;
}
-export function createRestaurant(request) {
+async function handleImageUpdate(request, previous) {
+ if (!previous) {
+ if (!request.imgURL) {
+ return "empty";
+ } else {
+ const img = await saveImage(request.imgURL);
+ return img;
+ }
+ } else {
+ if (request.imgURL == previous.imgUrl) {
+ return previous.imgUrl;
+ } else {
+ if (!request.imgURL) {
+ return previous.imgUrl;
+ } else {
+ const img = await saveImage(request.imgURL);
+ return img;
+ }
+ }
+ }
+}
+
+export async function createRestaurant(request, oldRestaurant) {
try {
- const restaurant = new Restaurant({
- _id: new mongoose.Types.ObjectId(),
- name: sanitizer.sanitize.keepUnicode(request.name),
- city: sanitizer.sanitize.keepUnicode(request.city),
- adress: sanitizer.sanitize.keepUnicode(request.adress),
- location: request.location,
- imgUrl: saveImage(request.imgURL),
- workingHours: request.workingHours,
- description: sanitizer.sanitize.keepUnicode(request.description),
- tags: request.tags,
- links: request.links,
- phone: request.phone,
- hidden: request.hidden,
- });
- return restaurant;
+ if (!oldRestaurant) {
+ const img = await handleImageUpdate(request);
+ const restaurant = new Restaurant({
+ _id: new mongoose.Types.ObjectId(),
+ name: sanitizer.sanitize.keepUnicode(request.name),
+ city: sanitizer.sanitize.keepUnicode(request.city),
+ adress: sanitizer.sanitize.keepUnicode(request.adress),
+ location: request.location,
+ imgUrl: img,
+ workingHours: request.workingHours,
+ description: sanitizer.sanitize.keepUnicode(request.description),
+ tags: request.tags,
+ links: request.links,
+ phone: request.phone,
+ hidden: request.hidden,
+ });
+ return restaurant;
+ } else {
+ const img = await handleImageUpdate(request, oldRestaurant);
+ const restaurant = new Restaurant({
+ name: sanitizer.sanitize.keepUnicode(request.name),
+ city: sanitizer.sanitize.keepUnicode(request.city),
+ dishes: oldRestaurant.dishes,
+ adress: sanitizer.sanitize.keepUnicode(request.adress),
+ location: request.location,
+ imgUrl: img,
+ workingHours: request.workingHours,
+ description: sanitizer.sanitize.keepUnicode(request.description),
+ tags: request.tags,
+ links: request.links,
+ phone: request.phone,
+ hidden: request.hidden,
+ });
+ return restaurant;
+ }
} catch (error) {
- throw newError("Invalid input data", 206);
+ console.log(error);
+ throw newError("Niewłaściwe dane", 206);
}
}
diff --git a/services/databaseServices.js b/services/databaseServices.js
index abc7c33..6507c50 100644
--- a/services/databaseServices.js
+++ b/services/databaseServices.js
@@ -41,7 +41,7 @@ export async function addDishToRestaurant(restaurantId, dishId) {
{ _id: restaurantId },
{ $push: { dishes: dishId } }
).catch((error) => {
- throw newError("Couldn't add dish to restaurant", 500);
+ throw newError("Nie udało się dodać dania do restauracji", 500);
});
}
@@ -49,16 +49,67 @@ export async function addRestaurantToUser(user, restaurant) {
await User.findByIdAndUpdate(user.id, {
$push: { restaurants: restaurant._id },
}).catch((e) => {
- throw newError("Couldn't add restaurant to user", 500);
+ throw newError("Nie udało się dodać restauracji do użytkownika", 500);
});
}
+function dueDateBasedOnSubscription(restaurant, monthsToAdd) {
+ let date;
+ if (
+ restaurant.subscriptionActive === false ||
+ !restaurant.subscriptionActive
+ ) {
+ date = new Date();
+ date.setMonth(date.getMonth() + monthsToAdd);
+ return date;
+ } else {
+ date = restaurant.subscriptionDue;
+ date.setMonth(date.getMonth() + monthsToAdd);
+ return date;
+ }
+}
+
+function startDate(restaurant) {
+ let date;
+ if (
+ restaurant.subscriptionActive === true &&
+ restaurant.subscriptionStarted
+ ) {
+ date = restaurant.subscriptionStarted;
+ return date;
+ } else {
+ date = new Date();
+ return date;
+ }
+}
+
+export async function renewSubscription(restaurantId, monthsToAdd) {
+ const restaurant = await Restaurant.findById(restaurantId).catch((err) => {
+ throw newError("Nie udało się pobrać restauracji.", 404);
+ });
+ const dueDate = dueDateBasedOnSubscription(restaurant, monthsToAdd);
+ const start = startDate(restaurant);
+ await Restaurant.findByIdAndUpdate(restaurantId, {
+ $set: {
+ subscriptionActive: true,
+ subscriptionDue: dueDate,
+ subscriptionStarted: start,
+ },
+ }).catch((e) => {
+ throw newError(
+ "Nie udało się przedłużyć subskrypcji, spróbuj ponownie.",
+ 500
+ );
+ });
+ return dueDateBasedOnSubscription(restaurant, monthsToAdd);
+}
+
export async function fetchRestaurant(id) {
let data;
await Restaurant.findById(id, (err, result) => {
data = result;
}).catch((e) => {
- throw newError("Couldn't fetch restaurant", 500);
+ throw newError("Nie udało się pobrać restauracji.", 500);
});
return data;
}
@@ -74,14 +125,14 @@ export async function fetchAllDishesForRestaurant(restaurant) {
export async function fetchDish(id) {
let data = await Dish.findById(id).catch((e) => {
- throw newError(`Couldn't fetch ${id}`, 404);
+ throw newError(`Nie udało się pobrać ${id}`, 404);
});
return data;
}
export async function fetchUser(email) {
- if (!email) throw newError("No input", 204);
+ if (!email) throw newError("Brak danych", 204);
const user = await User.findOne({ email: email });
- if (!user) throw newError("No such user...", 404);
+ if (!user) throw newError("Użytkownik nie istnieje", 404);
return user;
}
diff --git a/services/services.js b/services/services.js
index 28bdb54..007b781 100644
--- a/services/services.js
+++ b/services/services.js
@@ -88,13 +88,13 @@ export async function checkEmailTaken(email) {
export function validateUserToken(token) {
if (!token) throw newError("Brak dostępu", 401);
- const verified = jwt
- .verify(token, jwtSecret, { ignoreExpiration: false })
- .catch((e) => {
- throw newError("Brak dostępu", 401);
- });
- if (!verified) throw newError("Brak dostępu", 401);
- return verified;
+ try {
+ const verified = jwt.verify(token, jwtSecret, { ignoreExpiration: false });
+ if (!verified) throw newError("Brak dostępu", 401);
+ return verified;
+ } catch (error) {
+ throw newError("Brak dostępu", 401);
+ }
}
export async function validateDishId(id) {
@@ -142,17 +142,6 @@ export function yearFromNowDate() {
return date.addDays(365);
}
-export function halfYearFromNowDate() {
- Date.prototype.addDays = function (days) {
- var date = new Date(this.valueOf());
- date.setDate(date.getDate() + days);
- return date;
- };
- var nowDate = new Date();
- var resultDate = nowDate.addDays(183);
- return toShortDate(resultDate);
-}
-
export async function hashPass(pass) {
if (pass.length < 6) {
throw newError("Hasło za krótkie.", 500);
@@ -166,21 +155,6 @@ export async function hashPass(pass) {
}
}
-export function dueDateBasedOnSubscription(subscriptionActive) {
- if (subscriptionActive === true) {
- return halfYearFromNowDate();
- } else {
- return new Date();
- }
-}
-
-export function toShortDate(date) {
- if (!date) return false;
- const shortDate =
- date.getMonth() + "/" + date.getDay() + "/" + date.getFullYear();
- return shortDate;
-}
-
export async function saveImage(url) {
const newURL = await renameBlob(url);
return newURL;
diff --git a/services/services.test.js b/services/services.test.js
deleted file mode 100644
index b452632..0000000
--- a/services/services.test.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { toShortDate, generateNewPassword } from "./services";
-
-jest.mock("@azure/storage-blob", () => {
- return {
- StorageSharedKeyCredential: jest.fn(),
- newPipeline: jest.fn(),
- BlobServiceClient: jest.fn(),
- };
-});
-
-jest.mock("bcrypt", () => {
- return {
- foo: jest.fn(),
- };
-});
-
-test("should return false for no date on input", () => {
- expect(toShortDate()).toBe(false);
-});