diff --git a/package-lock.json b/package-lock.json
index a8be91d..61a5430 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "pwwa",
- "version": "1.1.2",
+ "version": "1.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pwwa",
- "version": "1.1.2",
+ "version": "1.2.0",
"dependencies": {
"@auth/prisma-adapter": "^1.4.0",
"@emotion/react": "^11.11.3",
@@ -16,7 +16,7 @@
"@mui/material": "^5.15.10",
"@mui/x-date-pickers": "^6.19.4",
"@premieroctet/next-crud": "^3.0.0",
- "@prisma/client": "^5.12.1",
+ "@prisma/client": "^5.13.0",
"@react-pdf/renderer": "^3.3.8",
"@tailwindcss/forms": "^0.5.7",
"@types/multer": "^1.4.11",
@@ -85,7 +85,8 @@
"uuid": "^9.0.1",
"web-push": "^3.6.7",
"webpack-bundle-analyzer": "^4.10.1",
- "winston": "^3.11.0",
+ "winston": "^3.13.0",
+ "winston-daily-rotate-file": "^5.0.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
"xlsx-style": "^0.8.13",
"xml-js": "^1.6.11",
@@ -94,7 +95,7 @@
"devDependencies": {
"cross-env": "^7.0.3",
"depcheck": "^1.4.7",
- "prisma": "^5.12.1"
+ "prisma": "^5.13.0"
}
},
"node_modules/@alloc/quick-lru": {
@@ -3760,9 +3761,9 @@
}
},
"node_modules/@prisma/client": {
- "version": "5.12.1",
- "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.12.1.tgz",
- "integrity": "sha512-6/JnizEdlSBxDIdiLbrBdMW5NqDxOmhXAJaNXiPpgzAPr/nLZResT6MMpbOHLo5yAbQ1Vv5UU8PTPRzb0WIxdA==",
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.13.0.tgz",
+ "integrity": "sha512-uYdfpPncbZ/syJyiYBwGZS8Gt1PTNoErNYMuqHDa2r30rNSFtgTA/LXsSk55R7pdRTMi5pHkeP9B14K6nHmwkg==",
"hasInstallScript": true,
"engines": {
"node": ">=16.13"
@@ -3777,39 +3778,39 @@
}
},
"node_modules/@prisma/debug": {
- "version": "5.12.1",
- "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.12.1.tgz",
- "integrity": "sha512-kd/wNsR0klrv79o1ITsbWxYyh4QWuBidvxsXSParPsYSu0ircUmNk3q4ojsgNc3/81b0ozg76iastOG43tbf8A==",
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.13.0.tgz",
+ "integrity": "sha512-699iqlEvzyCj9ETrXhs8o8wQc/eVW+FigSsHpiskSFydhjVuwTJEfj/nIYqTaWFYuxiWQRfm3r01meuW97SZaQ==",
"devOptional": true
},
"node_modules/@prisma/engines": {
- "version": "5.12.1",
- "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.12.1.tgz",
- "integrity": "sha512-HQDdglLw2bZR/TXD2Y+YfDMvi5Q8H+acbswqOsWyq9pPjBLYJ6gzM+ptlTU/AV6tl0XSZLU1/7F4qaWa8bqpJA==",
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.13.0.tgz",
+ "integrity": "sha512-hIFLm4H1boj6CBZx55P4xKby9jgDTeDG0Jj3iXtwaaHmlD5JmiDkZhh8+DYWkTGchu+rRF36AVROLnk0oaqhHw==",
"devOptional": true,
"hasInstallScript": true,
"dependencies": {
- "@prisma/debug": "5.12.1",
- "@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab",
- "@prisma/fetch-engine": "5.12.1",
- "@prisma/get-platform": "5.12.1"
+ "@prisma/debug": "5.13.0",
+ "@prisma/engines-version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
+ "@prisma/fetch-engine": "5.13.0",
+ "@prisma/get-platform": "5.13.0"
}
},
"node_modules/@prisma/engines-version": {
- "version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab",
- "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab.tgz",
- "integrity": "sha512-6yvO8s80Tym61aB4QNtYZfWVmE3pwqe807jEtzm8C5VDe7nw8O1FGX3TXUaXmWV0fQTIAfRbeL2Gwrndabp/0g==",
+ "version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
+ "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b.tgz",
+ "integrity": "sha512-AyUuhahTINGn8auyqYdmxsN+qn0mw3eg+uhkp8zwknXYIqoT3bChG4RqNY/nfDkPvzWAPBa9mrDyBeOnWSgO6A==",
"devOptional": true
},
"node_modules/@prisma/fetch-engine": {
- "version": "5.12.1",
- "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.12.1.tgz",
- "integrity": "sha512-qSs3KcX1HKcea1A+hlJVK/ljj0PNIUHDxAayGMvgJBqmaN32P9tCidlKz1EGv6WoRFICYnk3Dd/YFLBwnFIozA==",
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.13.0.tgz",
+ "integrity": "sha512-Yh4W+t6YKyqgcSEB3odBXt7QyVSm0OQlBSldQF2SNXtmOgMX8D7PF/fvH6E6qBCpjB/yeJLy/FfwfFijoHI6sA==",
"devOptional": true,
"dependencies": {
- "@prisma/debug": "5.12.1",
- "@prisma/engines-version": "5.12.0-21.473ed3124229e22d881cb7addf559799debae1ab",
- "@prisma/get-platform": "5.12.1"
+ "@prisma/debug": "5.13.0",
+ "@prisma/engines-version": "5.13.0-23.b9a39a7ee606c28e3455d0fd60e78c3ba82b1a2b",
+ "@prisma/get-platform": "5.13.0"
}
},
"node_modules/@prisma/generator-helper": {
@@ -3826,12 +3827,12 @@
"integrity": "sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA=="
},
"node_modules/@prisma/get-platform": {
- "version": "5.12.1",
- "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.12.1.tgz",
- "integrity": "sha512-pgIR+pSvhYHiUcqXVEZS31NrFOTENC9yFUdEAcx7cdQBoZPmHVjtjN4Ss6NzVDMYPrKJJ51U14EhEoeuBlMioQ==",
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.13.0.tgz",
+ "integrity": "sha512-B/WrQwYTzwr7qCLifQzYOmQhZcFmIFhR81xC45gweInSUn2hTEbfKUPd2keAog+y5WI5xLAFNJ3wkXplvSVkSw==",
"devOptional": true,
"dependencies": {
- "@prisma/debug": "5.12.1"
+ "@prisma/debug": "5.13.0"
}
},
"node_modules/@prisma/internals": {
@@ -7624,6 +7625,14 @@
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
},
+ "node_modules/file-stream-rotator": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/file-stream-rotator/-/file-stream-rotator-0.6.1.tgz",
+ "integrity": "sha512-u+dBid4PvZw17PmDeRcNOtCP9CCK/9lRN2w+r1xIS7yOL9JFrIBKTvrYsxT4P0pGtThYTn++QS5ChHaUov3+zQ==",
+ "dependencies": {
+ "moment": "^2.29.1"
+ }
+ },
"node_modules/file-type": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
@@ -14352,13 +14361,13 @@
"integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew=="
},
"node_modules/prisma": {
- "version": "5.12.1",
- "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.12.1.tgz",
- "integrity": "sha512-SkMnb6wyIxTv9ACqiHBI2u9gD6y98qXRoCoLEnZsF6yee5Qg828G+ARrESN+lQHdw4maSZFFSBPPDpvSiVTo0Q==",
+ "version": "5.13.0",
+ "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.13.0.tgz",
+ "integrity": "sha512-kGtcJaElNRAdAGsCNykFSZ7dBKpL14Cbs+VaQ8cECxQlRPDjBlMHNFYeYt0SKovAVy2Y65JXQwB3A5+zIQwnTg==",
"devOptional": true,
"hasInstallScript": true,
"dependencies": {
- "@prisma/engines": "5.12.1"
+ "@prisma/engines": "5.13.0"
},
"bin": {
"prisma": "build/index.js"
@@ -17763,9 +17772,9 @@
}
},
"node_modules/winston": {
- "version": "3.11.0",
- "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz",
- "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==",
+ "version": "3.13.0",
+ "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.0.tgz",
+ "integrity": "sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==",
"dependencies": {
"@colors/colors": "^1.6.0",
"@dabh/diagnostics": "^2.0.2",
@@ -17777,12 +17786,37 @@
"safe-stable-stringify": "^2.3.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
- "winston-transport": "^4.5.0"
+ "winston-transport": "^4.7.0"
},
"engines": {
"node": ">= 12.0.0"
}
},
+ "node_modules/winston-daily-rotate-file": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/winston-daily-rotate-file/-/winston-daily-rotate-file-5.0.0.tgz",
+ "integrity": "sha512-JDjiXXkM5qvwY06733vf09I2wnMXpZEhxEVOSPenZMii+g7pcDcTBt2MRugnoi8BwVSuCT2jfRXBUy+n1Zz/Yw==",
+ "dependencies": {
+ "file-stream-rotator": "^0.6.1",
+ "object-hash": "^3.0.0",
+ "triple-beam": "^1.4.1",
+ "winston-transport": "^4.7.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "peerDependencies": {
+ "winston": "^3"
+ }
+ },
+ "node_modules/winston-daily-rotate-file/node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/winston-transport": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz",
diff --git a/package.json b/package.json
index a9e5e94..6ff1a1e 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,7 @@
"@mui/material": "^5.15.10",
"@mui/x-date-pickers": "^6.19.4",
"@premieroctet/next-crud": "^3.0.0",
- "@prisma/client": "^5.12.1",
+ "@prisma/client": "^5.13.0",
"@react-pdf/renderer": "^3.3.8",
"@tailwindcss/forms": "^0.5.7",
"@types/multer": "^1.4.11",
@@ -102,7 +102,8 @@
"uuid": "^9.0.1",
"web-push": "^3.6.7",
"webpack-bundle-analyzer": "^4.10.1",
- "winston": "^3.11.0",
+ "winston": "^3.13.0",
+ "winston-daily-rotate-file": "^5.0.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
"xlsx-style": "^0.8.13",
"xml-js": "^1.6.11",
@@ -111,6 +112,6 @@
"devDependencies": {
"cross-env": "^7.0.3",
"depcheck": "^1.4.7",
- "prisma": "^5.12.1"
+ "prisma": "^5.13.0"
}
-}
\ No newline at end of file
+}
diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts
index 0760d19..2db98e9 100644
--- a/pages/api/auth/[...nextauth].ts
+++ b/pages/api/auth/[...nextauth].ts
@@ -145,11 +145,17 @@ export const authOptions: NextAuthOptions = {
user.id = dbUser.id;
//user.permissions = dbUser.permissions;
const session = { ...user };
+
+ await prisma.publisher.update({
+ where: { id: dbUser.id },
+ data: { lastLogin: new Date() }
+ });
return true; // Sign-in successful
} else {
// Optionally create a new user in your DB
// Or return false to deny access
- return false;
+ //Let's customize the error message to give a better user experience
+ throw new Error(`Твоят имейл '${user.email}' не е регистриран в системата. Моля свържи се с нас за да те регистрираме ако искаш да ползваш този имейл.`);
}
} catch (e) {
console.log(e);
diff --git a/pages/api/data/[...nextcrud].ts b/pages/api/data/[...nextcrud].ts
index af64fa7..c054391 100644
--- a/pages/api/data/[...nextcrud].ts
+++ b/pages/api/data/[...nextcrud].ts
@@ -8,6 +8,8 @@ import { authOptions } from "../auth/[...nextauth]";
const common = require("../../../src/helpers/common");
import jwt from 'jsonwebtoken';
import { decode } from 'next-auth/jwt';
+const logger = require('../../../src/logger');
+
// import { getToken } from "next-auth/jwt";
const handler = async (req: NextApiRequest, res: NextApiResponse) => {
@@ -25,6 +27,14 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
const authHeader = req.headers.authorization || '';
//console.log('authHeader', authHeader);
if (session) {
+ //get target table
+ const targetTable = req.query.nextcrud[0];
+ //get target action
+ if (req.method === 'DELETE') {
+
+ const targetId = req.query.nextcrud[1];
+ logger.info('[nextCrud] ' + targetTable + ': ' + targetId + 'DELETED by ' + session.user.email);
+ }
return nextCrudHandler(req, res);
}
else {
diff --git a/pages/cart/calendar/index.tsx b/pages/cart/calendar/index.tsx
index 6ad9127..da3bc2f 100644
--- a/pages/cart/calendar/index.tsx
+++ b/pages/cart/calendar/index.tsx
@@ -677,7 +677,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
list of publishers for the selected date with availabilities
------------------AVAILABLE PUBLISHERS LIST FOR THE SELECTED DATE0 ------------------ */}
-
+
Достъпни за този ден: {availablePubs.length}
@@ -719,7 +719,7 @@ export default function CalendarPage({ initialEvents, initialShifts }) {
return (
diff --git a/pages/cart/publishers/stats.tsx b/pages/cart/publishers/stats.tsx
index 835c79a..3486a3f 100644
--- a/pages/cart/publishers/stats.tsx
+++ b/pages/cart/publishers/stats.tsx
@@ -39,6 +39,7 @@ function ContactsPage({ publishers, allPublishers }) {
Име
Възможности
Участия
+ Последно влизане
@@ -67,6 +68,7 @@ function ContactsPage({ publishers, allPublishers }) {
+ {pub.lastLogin ? new Date(pub.lastLogin).toLocaleString("bg") : ""}
>
) : (
<>
@@ -125,7 +127,7 @@ export const getServerSideProps = async (context) => {
const prisma = common.getPrismaClient();
const dateStr = new Date().toISOString().split('T')[0];
- let publishers = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth', dateStr, false, true, true);
+ let publishers = await data.filterPublishersNew('id,firstName,lastName,email,isActive,desiredShiftsPerMonth,lastLogin', dateStr, false, true, true, true);
// const axios = await axiosServer(context);
// const { data: publishers } = await axios.get(`api/?action=filterPublishers&assignments=true&availabilities=true&date=${dateStr}&select=id,firstName,lastName,isActive,desiredShiftsPerMonth`);
@@ -158,6 +160,7 @@ export const getServerSideProps = async (context) => {
}
}
});
+ publisher.lastLogin = publisher.lastLogin ? publisher.lastLogin.toISOString() : null;
//remove availabilities that isFromPreviousAssignment
publisher.availabilities = publisher.availabilities.filter(availability => !availability.isFromPreviousAssignment);
@@ -175,6 +178,7 @@ export const getServerSideProps = async (context) => {
phone: true,
isActive: true,
desiredShiftsPerMonth: true,
+ lastLogin: true,
assignments: {
select: {
id: true,
@@ -211,6 +215,7 @@ export const getServerSideProps = async (context) => {
publisher.currentMonthAssignments = countAssignments(publisher.assignments, currentMonthStart, currentMonthEnd);
publisher.previousMonthAssignments = countAssignments(publisher.assignments, previousMonthStart, previousMonthEnd);
+ publisher.lastLogin = publisher.lastLogin ? publisher.lastLogin.toISOString() : null;
// Convert date formats within the same iteration
convertShiftDates(publisher.assignments);
});
diff --git a/pages/dash.tsx b/pages/dash.tsx
index fb3a2f7..5e71550 100644
--- a/pages/dash.tsx
+++ b/pages/dash.tsx
@@ -63,9 +63,9 @@ export default function IndexPage({ initialItems, initialUserId }: IProps) {
-
+
-
+
diff --git a/prisma/migrations/20240425155607_add_publisher_last_login/migration.sql b/prisma/migrations/20240425155607_add_publisher_last_login/migration.sql
new file mode 100644
index 0000000..60c9a86
--- /dev/null
+++ b/prisma/migrations/20240425155607_add_publisher_last_login/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE `publisher` ADD COLUMN `lastLogin` DATETIME(3) NULL;
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 5b91e47..25ce5dd 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -122,6 +122,7 @@ model Publisher {
reports Report[]
Message Message[]
EventLog EventLog[]
+ lastLogin DateTime?
}
model Availability {
diff --git a/src/helpers/data.js b/src/helpers/data.js
index 0bdb57f..972ddb1 100644
--- a/src/helpers/data.js
+++ b/src/helpers/data.js
@@ -228,7 +228,7 @@ async function getAvailabilities(userId) {
}
-async function filterPublishersNew(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isWithStats = true, includeOldAvailabilities = false) {
+async function filterPublishersNew(selectFields, filterDate, isExactTime = false, isForTheMonth = false, isNoEndDateFilter = false, isWithStats = true, includeOldAvailabilities = false) {
filterDate = new Date(filterDate); // Convert to date object if not already
@@ -341,7 +341,7 @@ async function filterPublishersNew(selectFields, filterDate, isExactTime = false
{
dayOfMonth: { not: null },
startTime: { gte: monthInfo.firstMonday },
- endTime: { lte: monthInfo.lastSunday }
+ // endTime: { lte: monthInfo.lastSunday }
},
// Check if dayOfMonth is null and match by day of week using the enum (Assigments every week)
{
@@ -358,6 +358,10 @@ async function filterPublishersNew(selectFields, filterDate, isExactTime = false
]
}
};
+
+ if (!isNoEndDateFilter) { // Check if we need to apply the endTime filter
+ whereClause["availabilities"].some.OR[0].endTime = { lte: monthInfo.lastSunday };
+ }
}
console.log(`getting publishers for date: ${filterDate}, isExactTime: ${isExactTime}, isForTheMonth: ${isForTheMonth}`);
diff --git a/src/logger.js b/src/logger.js
new file mode 100644
index 0000000..eff500b
--- /dev/null
+++ b/src/logger.js
@@ -0,0 +1,25 @@
+const winston = require('winston');
+require('winston-daily-rotate-file');
+
+const logConfiguration = {
+ 'transports': [
+ new winston.transports.DailyRotateFile({
+ filename: './logs/application-%DATE%.log',
+ datePattern: 'YYYY-MM-DD-HH',
+ zippedArchive: true,
+ maxSize: '20m',
+ maxFiles: '90d',
+ level: 'info'
+ })
+ ],
+ format: winston.format.combine(
+ winston.format.timestamp({
+ format: 'YYYY-MM-DD HH:mm:ss'
+ }),
+ winston.format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`)
+ )
+};
+
+const logger = winston.createLogger(logConfiguration);
+
+module.exports = logger;