From 7a7d3bb50e0ddaee5e027b0aef1d388583ae9077 Mon Sep 17 00:00:00 2001 From: anshuk Date: Sun, 30 Jul 2023 22:42:26 +0530 Subject: [PATCH] v0.3.0-dev - Version bumped to 0.3.0 - NextAuth.js Introduced - OAuth now works with MMDL! - Supports Keycloak, Google, Authentik out of the box. The rest (those supported by NextAuth.js) can be added manually by the user. - Sequelize formally introduced - Models and migrations generated - Bug fixes --- .dockerignore | 15 +- .gitignore | 16 +- .sequelizerc | 7 + CHANGELOG | 9 + COMMITMESSAGE.md | 11 +- config/config.js | 27 ++ config/nextAuthProviders.js | 48 +++ .../template spec -- passes (failed).png | Bin 0 -> 38647 bytes cypress/videos/install.cy.ts.mp4 | Bin 0 -> 8989 bytes migrations/20230728075614-first_migration.js | 303 ++++++++++++++++++ ...3903-users-add-columns-nextAuth-v-0.3.0.js | 54 ++++ migrations/20230730093908-create-session.js | 38 +++ migrations/20230730094838-create-account.js | 36 +++ models/account.js | 36 +++ models/caldav_accounts.ts | 77 +++++ models/calendar_events.ts | 83 +++++ models/calendars.ts | 107 +++++++ models/custom_filters.ts | 59 ++++ models/index.js | 43 +++ models/init-models.ts | 77 +++++ models/labels.ts | 59 ++++ models/otp_table.ts | 71 ++++ models/session.js | 22 ++ models/settings.ts | 65 ++++ models/ssid_table.ts | 59 ++++ models/users.ts | 119 +++++++ package-lock.json | 200 +++++++++++- package.json | 7 +- src/components/Home/HomeTasks/HomeTasks.tsx | 8 +- src/components/LabelManager.js | 15 +- .../AppBarGenericClass.js} | 40 ++- src/components/common/AppBar/index.tsx | 16 + src/components/common/AppBarGeneric copy.js | 89 ----- src/components/common/GenericLists.js | 14 +- .../common/calendars/ShowCalendarList.js | 31 +- .../caldavAccounts/CaldavAccounts.js | 3 +- src/components/filters/AddFilter.js | 1 - src/components/filters/FilterList.js | 30 +- src/components/fullcalendar/DashboardView.js | 55 ++-- .../page/CalendarViewPage/CalendarView.js} | 5 +- src/components/page/CombinedView.js | 4 +- .../page/ManageFiltersPage/ManageFilters.js} | 37 ++- .../page/MangerLabelsPage/ManageLabels.js} | 7 +- .../page/SettingsPage/SettingsPage.js} | 22 +- .../page/TaskViewPage/TaskViewList.js} | 2 +- src/components/tasks/TaskList.js | 66 ++-- src/components/tasks/TaskUI.js | 10 +- src/config/constants.js | 2 +- src/helpers/api/installSequelize.ts | 14 + src/helpers/api/user.js | 110 +++++-- src/helpers/frontend/classes/APIRequests.js | 29 +- src/helpers/frontend/cookies.js | 13 + src/helpers/frontend/user.js | 68 ++++ src/helpers/installation.ts | 3 + src/helpers/models.ts | 4 + src/helpers/thirdparty/keycloak.ts | 70 ++++ src/helpers/thirdparty/nextAuth.ts | 26 ++ src/i18n/strings.json | 1 + src/pages/_app.js | 16 +- src/pages/accounts/caldav.js | 24 +- src/pages/accounts/settings.tsx | 35 ++ src/pages/api/admin/deleteuser.js | 13 +- src/pages/api/admin/getusers.js | 12 +- src/pages/api/auth/[...nextauth].js | 22 ++ src/pages/api/auth/inbuilt/check.js | 15 + src/pages/api/caldav/calendars/add/event.js | 13 +- src/pages/api/caldav/calendars/events/all.js | 15 +- .../api/caldav/calendars/events/db/all.js | 15 +- .../api/caldav/calendars/events/db/index.js | 15 +- .../caldav/calendars/events/fetchevents.js | 14 +- .../api/caldav/calendars/events/refresh.js | 15 +- src/pages/api/caldav/calendars/index.js | 12 +- .../api/caldav/calendars/labels/index.js | 13 +- .../api/caldav/calendars/modify/object.js | 14 +- src/pages/api/caldav/calendars/name.js | 14 +- src/pages/api/caldav/calendars/sync/all.js | 15 +- src/pages/api/caldav/calendars/sync/one.js | 15 +- src/pages/api/caldav/delete.js | 12 +- src/pages/api/caldav/event/delete.js | 14 +- src/pages/api/caldav/index.js | 14 +- src/pages/api/caldav/register.js | 20 +- src/pages/api/calendars/create.js | 13 +- src/pages/api/calendars/refresh.js | 13 +- src/pages/api/events/fetchOne.js | 12 +- src/pages/api/events/search.js | 13 +- src/pages/api/filters/add.js | 11 +- src/pages/api/filters/delete.js | 11 +- src/pages/api/filters/get.js | 13 +- src/pages/api/filters/modify.js | 13 +- src/pages/api/labels/modifycolor.js | 11 +- src/pages/api/labels/updatecache.js | 13 +- src/pages/api/misc/generateics.js | 2 +- src/pages/api/misc/parseics.js | 2 +- src/pages/api/misc/parseics_ical.js | 2 +- src/pages/api/settings/get.js | 12 +- src/pages/api/settings/getone.js | 12 +- src/pages/api/settings/modify.js | 11 +- src/pages/api/tasks/rrule/getrepeatobj.js | 12 +- src/pages/api/tasks/rrule/postrepeatobj.js | 12 +- src/pages/api/users/info.js | 12 +- src/pages/api/users/register.js | 2 + src/pages/calendar/view.tsx | 35 ++ src/pages/filters/manage.tsx | 35 ++ src/pages/index.js | 63 ++-- src/pages/labels/manage.tsx | 35 ++ src/pages/tasks/list.tsx | 35 ++ 106 files changed, 2773 insertions(+), 442 deletions(-) create mode 100644 .sequelizerc create mode 100644 config/config.js create mode 100644 config/nextAuthProviders.js create mode 100644 cypress/screenshots/install.cy.ts/template spec -- passes (failed).png create mode 100644 cypress/videos/install.cy.ts.mp4 create mode 100644 migrations/20230728075614-first_migration.js create mode 100644 migrations/20230730083903-users-add-columns-nextAuth-v-0.3.0.js create mode 100644 migrations/20230730093908-create-session.js create mode 100644 migrations/20230730094838-create-account.js create mode 100644 models/account.js create mode 100644 models/caldav_accounts.ts create mode 100644 models/calendar_events.ts create mode 100644 models/calendars.ts create mode 100644 models/custom_filters.ts create mode 100644 models/index.js create mode 100644 models/init-models.ts create mode 100644 models/labels.ts create mode 100644 models/otp_table.ts create mode 100644 models/session.js create mode 100644 models/settings.ts create mode 100644 models/ssid_table.ts create mode 100644 models/users.ts rename src/components/common/{AppBarGeneric.js => AppBar/AppBarGenericClass.js} (89%) create mode 100644 src/components/common/AppBar/index.tsx delete mode 100644 src/components/common/AppBarGeneric copy.js rename src/{pages/calendar/view.js => components/page/CalendarViewPage/CalendarView.js} (93%) rename src/{pages/filters/manage.js => components/page/ManageFiltersPage/ManageFilters.js} (87%) rename src/{pages/labels/manage.js => components/page/MangerLabelsPage/ManageLabels.js} (84%) rename src/{pages/accounts/settings.js => components/page/SettingsPage/SettingsPage.js} (95%) rename src/{pages/tasks/list.js => components/page/TaskViewPage/TaskViewList.js} (99%) create mode 100644 src/helpers/api/installSequelize.ts create mode 100644 src/helpers/installation.ts create mode 100644 src/helpers/models.ts create mode 100644 src/helpers/thirdparty/keycloak.ts create mode 100644 src/helpers/thirdparty/nextAuth.ts create mode 100644 src/pages/accounts/settings.tsx create mode 100644 src/pages/api/auth/[...nextauth].js create mode 100644 src/pages/api/auth/inbuilt/check.js create mode 100644 src/pages/calendar/view.tsx create mode 100644 src/pages/filters/manage.tsx create mode 100644 src/pages/labels/manage.tsx create mode 100644 src/pages/tasks/list.tsx diff --git a/.dockerignore b/.dockerignore index 9c1a3cc..22d669a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -11,12 +11,13 @@ docs config/config.json package-withSequelize.json +temp/ #Sequelise Temporary Ignore list -models/ -config/ -migrations/ -src/helpers/api/installSequelize.ts -src/helpers/installation.ts -src/helpers/models.ts -.sequelizerc +# models/ +# config/ +# migrations/ +# src/helpers/api/installSequelize.ts +# src/helpers/installation.ts +# src/helpers/models.ts +# .sequelizerc diff --git a/.gitignore b/.gitignore index c0706d6..478bb1a 100644 --- a/.gitignore +++ b/.gitignore @@ -46,12 +46,12 @@ COMBINEDCOMMITMESSAGE config/config.json package-withSequelize.json - +temp/ #Sequelise Temporary Ignore list -models/ -config/ -migrations/ -src/helpers/api/installSequelize.ts -src/helpers/installation.ts -src/helpers/models.ts -.sequelizerc +# models/ +# config/ +# migrations/ +# src/helpers/api/installSequelize.ts +# src/helpers/installation.ts +# src/helpers/models.ts +# .sequelizerc diff --git a/.sequelizerc b/.sequelizerc new file mode 100644 index 0000000..3157456 --- /dev/null +++ b/.sequelizerc @@ -0,0 +1,7 @@ +const path = require('path'); + +module.exports = { + env: process.env.NODE_ENV, + 'config': path.resolve('config', 'config.js'), + +} \ No newline at end of file diff --git a/CHANGELOG b/CHANGELOG index 4507a34..1c4f4c9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,12 @@ +v0.3.0-dev + - Version bumped to 0.3.0 + - NextAuth.js Introduced + - OAuth now works with MMDL! + - Supports Keycloak, Google, Authentik out of the box. The rest (those supported by NextAuth.js) can be added manually by the user. + - Sequelize formally introduced + - Models and migrations generated + - Bug fixes + v0.1.9 - Removed Fullcalendar script import from _app.js - Looks like calendar view works without it. diff --git a/COMMITMESSAGE.md b/COMMITMESSAGE.md index ca25edf..45d6c67 100644 --- a/COMMITMESSAGE.md +++ b/COMMITMESSAGE.md @@ -1,3 +1,8 @@ -admin/getusers API Changes -- Added dev dependencies to make cypress work. -- Added eslint dependencies \ No newline at end of file +v0.3.0-dev + - Version bumped to 0.3.0 + - NextAuth.js Introduced + - OAuth now works with MMDL! + - Supports Keycloak, Google, Authentik out of the box. The rest (those supported by NextAuth.js) can be added manually by the user. + - Sequelize formally introduced + - Models and migrations generated + - Bug fixes \ No newline at end of file diff --git a/config/config.js b/config/config.js new file mode 100644 index 0000000..423dea7 --- /dev/null +++ b/config/config.js @@ -0,0 +1,27 @@ +const dotenv = require('dotenv') +dotenv.config({ path: `.env.local`, override: true }); +module.exports = { + local: { + username: process.env.DB_USER, + password: process.env.DB_PASS, + database: process.env.DB_NAME, + host: process.env.DB_HOST, + port: 3306, + dialect: "mysql" + }, + test: { + username: "root", + password: null, + database: "database_test", + host: "127.0.0.1", + dialect: "mysql" + }, + production: { + username: "root", + password: null, + database: "database_production", + host: "127.0.0.1", + dialect: "mysql" + } +} + diff --git a/config/nextAuthProviders.js b/config/nextAuthProviders.js new file mode 100644 index 0000000..54412e7 --- /dev/null +++ b/config/nextAuthProviders.js @@ -0,0 +1,48 @@ +import KeycloakProvider from "next-auth/providers/keycloak"; +import GoogleProvider from 'next-auth/providers/google' +import AuthentikProvider from 'next-auth/providers/authentik' +import { varNotEmpty } from "@/helpers/general"; + +/** + * Array of authProviders that will be passed to NextAuth.js + */ +const authProviders = [] + +/** + * Add KeyCloak if parameters are defined. + */ +if(varNotEmpty(process.env.KEYCLOAK_CLIENT_ID) && varNotEmpty(process.env.KEYCLOAK_ISSUER_URL) && varNotEmpty(process.env.KEYCLOAK_CLIENT_SECRET)){ + authProviders.push( + KeycloakProvider({ + clientId: process.env.KEYCLOAK_CLIENT_ID, + issuer: process.env.KEYCLOAK_ISSUER_URL, + clientSecret: process.env.KEYCLOAK_CLIENT_SECRET + }), + ) +} + +/** + * Add Google Provider if parameters are defined. +*/ +if(varNotEmpty(process.env.GOOGLE_CLIENT_ID) && varNotEmpty(process.env.GOOGLE_CLIENT_SECRET) ){ + authProviders.push( + GoogleProvider({ + clientId: process.env.GOOGLE_CLIENT_ID, + clientSecret: process.env.GOOGLE_CLIENT_SECRET + }) + ) +} +/** + * Add Authentik Provider if parameters are defined. +*/ +if(varNotEmpty(process.env.AUTHENTIK_CLIENT_ID) && varNotEmpty(process.env.AUTHENTIK_CLIENT_SECRET) && varNotEmpty(process.env.AUTHENTIK_ISSUER)){ + + authProviders.push( + AuthentikProvider({ + clientId: process.env.AUTHENTIK_CLIENT_ID, + clientSecret: process.env.AUTHENTIK_CLIENT_SECRET, + issuer: process.env.AUTHENTIK_ISSUER, + }) + ) +} +export default authProviders \ No newline at end of file diff --git a/cypress/screenshots/install.cy.ts/template spec -- passes (failed).png b/cypress/screenshots/install.cy.ts/template spec -- passes (failed).png new file mode 100644 index 0000000000000000000000000000000000000000..1d5f87dc3333f323b024bfbb36a010765a673247 GIT binary patch literal 38647 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 literal 0 HcmV?d00001 diff --git a/cypress/videos/install.cy.ts.mp4 b/cypress/videos/install.cy.ts.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..e2aed9ac65e8aec395b2f23e409207086a136d9d GIT binary patch literal 8989 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 F{6C;7@Xr7M literal 0 HcmV?d00001 diff --git a/migrations/20230728075614-first_migration.js b/migrations/20230728075614-first_migration.js new file mode 100644 index 0000000..3a52146 --- /dev/null +++ b/migrations/20230728075614-first_migration.js @@ -0,0 +1,303 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up (queryInterface, Sequelize) { + await queryInterface.createTable('users', { + users_id: { + autoIncrement: true, + type: Sequelize.INTEGER, + primaryKey: true + }, + username: { + type: Sequelize.STRING(45), + allowNull: true + }, + email: { + type: Sequelize.STRING(45), + allowNull: true + }, + password: { + type: Sequelize.STRING(1000), + allowNull: true + }, + created: { + type: Sequelize.STRING(45), + allowNull: true + }, + level: { + type: Sequelize.STRING(45), + allowNull: true + }, + userhash: { + type: Sequelize.STRING(1000), + allowNull: true + }, + mobile: { + type: Sequelize.STRING(45), + allowNull: true + } + + }); + + await queryInterface.createTable('caldav_accounts', { + caldav_accounts_id: { + autoIncrement: true, + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true + }, + username: { + type: Sequelize.STRING(45), + allowNull: true + }, + password: { + type: Sequelize.STRING(3000), + allowNull: true + }, + url: { + type: Sequelize.STRING(1000), + allowNull: true + }, + userid: { + type: Sequelize.STRING(45), + allowNull: true + }, + name: { + type: Sequelize.STRING(100), + allowNull: true + }, + authMethod: { + type: Sequelize.STRING(45), + allowNull: true + } + + }) + + await queryInterface.createTable('calendar_events', { + calendar_events_id: { + autoIncrement: true, + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true + }, + url: { + type: Sequelize.STRING(3000), + allowNull: true + }, + etag: { + type: Sequelize.STRING(1000), + allowNull: true + }, + data: { + type: Sequelize.STRING(5000), + allowNull: true + }, + updated: { + type: Sequelize.STRING(45), + allowNull: true + }, + type: { + type: Sequelize.STRING(45), + allowNull: true + }, + calendar_id: { + type: Sequelize.STRING(45), + allowNull: true + }, + deleted: { + type: Sequelize.STRING(45), + allowNull: true + } + + }) + + await queryInterface.createTable('calendars', { + calendars_id: { + autoIncrement: true, + type: Sequelize.BIGINT, + allowNull: false, + primaryKey: true + }, + displayName: { + type: Sequelize.STRING(45), + allowNull: true + }, + url: { + type: Sequelize.STRING(200), + allowNull: true + }, + ctag: { + type: Sequelize.STRING(200), + allowNull: true + }, + description: { + type: Sequelize.STRING(45), + allowNull: true + }, + calendarColor: { + type: Sequelize.STRING(45), + allowNull: true + }, + syncToken: { + type: Sequelize.STRING(200), + allowNull: true + }, + timezone: { + type: Sequelize.STRING(45), + allowNull: true + }, + reports: { + type: Sequelize.STRING(2000), + allowNull: true + }, + resourcetype: { + type: Sequelize.STRING(45), + allowNull: true + }, + caldav_accounts_id: { + type: Sequelize.STRING(45), + allowNull: true + }, + updated: { + type: Sequelize.STRING(45), + allowNull: true + } + }) + + await queryInterface.createTable('custom_filters', { + custom_filters_id: { + autoIncrement: true, + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true + }, + name: { + type: Sequelize.STRING(100), + allowNull: true + }, + filtervalue: { + type: Sequelize.STRING(1000), + allowNull: true + }, + userid: { + type: Sequelize.STRING(45), + allowNull: true + } + + }) + + await queryInterface.createTable('labels', { + labels_id: { + autoIncrement: true, + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true + }, + name: { + type: Sequelize.STRING(45), + allowNull: true + }, + colour: { + type: Sequelize.STRING(45), + allowNull: true + }, + userid: { + type: Sequelize.STRING(45), + allowNull: true + } + }) + + await queryInterface.createTable('otp_table', { + otp_table_id: { + autoIncrement: true, + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true + }, + userid: { + type: Sequelize.STRING(45), + allowNull: true + }, + otp: { + type: Sequelize.STRING(45), + allowNull: true + }, + created: { + type: Sequelize.STRING(45), + allowNull: true + }, + type: { + type: Sequelize.STRING(45), + allowNull: true + }, + reqid: { + type: Sequelize.STRING(2000), + allowNull: true + } + + }) + + await queryInterface.createTable('settings', { + settings_id: { + autoIncrement: true, + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true + }, + name: { + type: Sequelize.STRING(200), + allowNull: true + }, + userid: { + type: Sequelize.STRING(45), + allowNull: true + }, + global: { + type: Sequelize.STRING(45), + allowNull: true + }, + value: { + type: Sequelize.STRING(1000), + allowNull: true + } + + }) + + await queryInterface.createTable('ssid_table', { + ssid_table_id: { + autoIncrement: true, + type: Sequelize.INTEGER, + allowNull: false, + primaryKey: true + }, + userhash: { + type: Sequelize.STRING(1000), + allowNull: true + }, + ssid: { + type: Sequelize.STRING(1000), + allowNull: true + }, + created: { + type: Sequelize.STRING(45), + allowNull: true + } + + }) + + }, + async down (queryInterface, Sequelize) { + await queryInterface.dropTable('users'); + await queryInterface.dropTable('caldav_accounts'); + await queryInterface.dropTable('calendar_events'); + await queryInterface.dropTable('calendars'); + await queryInterface.dropTable('custom_filters'); + await queryInterface.dropTable('labels'); + await queryInterface.dropTable('otp_table'); + await queryInterface.dropTable('settings'); + await queryInterface.dropTable('ssid_table'); + + + } +}; diff --git a/migrations/20230730083903-users-add-columns-nextAuth-v-0.3.0.js b/migrations/20230730083903-users-add-columns-nextAuth-v-0.3.0.js new file mode 100644 index 0000000..8ed0bef --- /dev/null +++ b/migrations/20230730083903-users-add-columns-nextAuth-v-0.3.0.js @@ -0,0 +1,54 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up (queryInterface, Sequelize) { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + + queryInterface.addColumn("users", "id",{ + type: Sequelize.DataTypes.UUID, + defaultValue: Sequelize.DataTypes.UUIDV4, + + }, + {transaction: t}), + queryInterface.addColumn("users", "expires",{ + type: Sequelize.DataTypes.DATE, + }, {transaction: t}), + queryInterface.addColumn("users", "session_token",{ + type: Sequelize.DataTypes.STRING, + unique: "sessionToken", + }, {transaction: t}), + queryInterface.addColumn("users", "name",{ + type: Sequelize.DataTypes.STRING + }, {transaction: t}), + queryInterface.addColumn("users", "email_verified",{ + type: Sequelize.DataTypes.STRING, + }, {transaction: t}), + queryInterface.addColumn("users", "image",{ + type: Sequelize.DataTypes.STRING, + }, {transaction: t}), + + + + + ]); + }); +}, + + async down (queryInterface, Sequelize) { + return queryInterface.sequelize.transaction(t => { + return Promise.all([ + queryInterface.removeColumn("users", "id",{transaction:t}), + queryInterface.removeColumn("users", "session_token",{transaction:t}), + queryInterface.removeColumn("users", "expires",{transaction:t}), + queryInterface.removeColumn("users", "name",{transaction:t}), + queryInterface.removeColumn("users", "email_verified",{transaction:t}), + queryInterface.removeColumn("users", "image",{transaction:t}) + + + ]) + }) + + } +}; diff --git a/migrations/20230730093908-create-session.js b/migrations/20230730093908-create-session.js new file mode 100644 index 0000000..22b9642 --- /dev/null +++ b/migrations/20230730093908-create-session.js @@ -0,0 +1,38 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('sessions', { + id: { + allowNull: false, + primaryKey: true, + defaultValue: Sequelize.UUIDV4, + type: Sequelize.UUID + }, + timestamp: { + type: Sequelize.DATE + }, + expires: { type: Sequelize.DATE, allowNull: false }, + session_token: { + type: Sequelize.STRING, + unique: "sessionToken", + allowNull: false, }, + user_id: { + type: Sequelize.UUID + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue:Sequelize.fn('now') + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue:Sequelize.fn('now') + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('sessions'); + } +}; \ No newline at end of file diff --git a/migrations/20230730094838-create-account.js b/migrations/20230730094838-create-account.js new file mode 100644 index 0000000..e4a58ca --- /dev/null +++ b/migrations/20230730094838-create-account.js @@ -0,0 +1,36 @@ +'use strict'; +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.createTable('accounts', { + id: { + type: Sequelize.UUID, + defaultValue: Sequelize.UUIDV4, + primaryKey: true, + }, + type: { type: Sequelize.STRING, allowNull: false }, + provider: { type: Sequelize.STRING, allowNull: false }, + provider_account_id: { type: Sequelize.STRING, allowNull: false }, + refresh_token: { type: Sequelize.TEXT }, + access_token: { type: Sequelize.TEXT }, + expires_at: { type: Sequelize.INTEGER }, + token_type: { type: Sequelize.STRING }, + scope: { type: Sequelize.STRING }, + id_token: { type: Sequelize.TEXT }, + session_state: { type: Sequelize.STRING }, + user_id: { type: Sequelize.UUID }, + createdAt: { + type: Sequelize.DATE, + defaultValue:Sequelize.fn('now'), + }, + updatedAt: { + type: Sequelize.DATE, + defaultValue:Sequelize.fn('now'), + + } + }); + }, + async down(queryInterface, Sequelize) { + await queryInterface.dropTable('accounts'); + } +}; \ No newline at end of file diff --git a/models/account.js b/models/account.js new file mode 100644 index 0000000..5c7bfea --- /dev/null +++ b/models/account.js @@ -0,0 +1,36 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Account extends Model { + /** + * Helper method for defining associations. + * This method is not a part of Sequelize lifecycle. + * The `models/index` file will call this method automatically. + */ + static associate(models) { + // define association here + } + } + Account.init({ + id: DataTypes.UUID, + user_id: DataTypes.UUID, + type: DataTypes.STRING, + provider: DataTypes.STRING, + provider_account_id: DataTypes.STRING, + refresh_token: DataTypes.TEXT, + access_token: DataTypes.TEXT, + expires_at: DataTypes.NUMBER, + token_type: DataTypes.STRING, + scope: DataTypes.STRING, + id_token: DataTypes.TEXT, + session_state: DataTypes.STRING, + createdAt:DataTypes.DATE, + updatedAt:DataTypes.DATE + }, { + sequelize, + modelName: 'account', + }); + return Account; +}; \ No newline at end of file diff --git a/models/caldav_accounts.ts b/models/caldav_accounts.ts new file mode 100644 index 0000000..d249e79 --- /dev/null +++ b/models/caldav_accounts.ts @@ -0,0 +1,77 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface caldav_accountsAttributes { + caldav_accounts_id: number; + username?: string; + password?: string; + url?: string; + userid?: string; + name?: string; + authMethod?: string; +} + +export type caldav_accountsPk = "caldav_accounts_id"; +export type caldav_accountsId = caldav_accounts[caldav_accountsPk]; +export type caldav_accountsOptionalAttributes = "caldav_accounts_id" | "username" | "password" | "url" | "userid" | "name" | "authMethod"; +export type caldav_accountsCreationAttributes = Optional; + +export class caldav_accounts extends Model implements caldav_accountsAttributes { + caldav_accounts_id!: number; + username?: string; + password?: string; + url?: string; + userid?: string; + name?: string; + authMethod?: string; + + + static initModel(sequelize: Sequelize.Sequelize): typeof caldav_accounts { + return caldav_accounts.init({ + caldav_accounts_id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + username: { + type: DataTypes.STRING(45), + allowNull: true + }, + password: { + type: DataTypes.STRING(3000), + allowNull: true + }, + url: { + type: DataTypes.STRING(1000), + allowNull: true + }, + userid: { + type: DataTypes.STRING(45), + allowNull: true + }, + name: { + type: DataTypes.STRING(100), + allowNull: true + }, + authMethod: { + type: DataTypes.STRING(45), + allowNull: true + } + }, { + sequelize, + tableName: 'caldav_accounts', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "caldav_accounts_id" }, + ] + }, + ] + }); + } +} diff --git a/models/calendar_events.ts b/models/calendar_events.ts new file mode 100644 index 0000000..945ccb0 --- /dev/null +++ b/models/calendar_events.ts @@ -0,0 +1,83 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface calendar_eventsAttributes { + calendar_events_id: number; + url?: string; + etag?: string; + data?: string; + updated?: string; + type?: string; + calendar_id?: string; + deleted?: string; +} + +export type calendar_eventsPk = "calendar_events_id"; +export type calendar_eventsId = calendar_events[calendar_eventsPk]; +export type calendar_eventsOptionalAttributes = "calendar_events_id" | "url" | "etag" | "data" | "updated" | "type" | "calendar_id" | "deleted"; +export type calendar_eventsCreationAttributes = Optional; + +export class calendar_events extends Model implements calendar_eventsAttributes { + calendar_events_id!: number; + url?: string; + etag?: string; + data?: string; + updated?: string; + type?: string; + calendar_id?: string; + deleted?: string; + + + static initModel(sequelize: Sequelize.Sequelize): typeof calendar_events { + return calendar_events.init({ + calendar_events_id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + url: { + type: DataTypes.STRING(3000), + allowNull: true + }, + etag: { + type: DataTypes.STRING(1000), + allowNull: true + }, + data: { + type: DataTypes.STRING(5000), + allowNull: true + }, + updated: { + type: DataTypes.STRING(45), + allowNull: true + }, + type: { + type: DataTypes.STRING(45), + allowNull: true + }, + calendar_id: { + type: DataTypes.STRING(45), + allowNull: true + }, + deleted: { + type: DataTypes.STRING(45), + allowNull: true + } + }, { + sequelize, + tableName: 'calendar_events', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "calendar_events_id" }, + ] + }, + ] + }); + } +} diff --git a/models/calendars.ts b/models/calendars.ts new file mode 100644 index 0000000..80fd980 --- /dev/null +++ b/models/calendars.ts @@ -0,0 +1,107 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface calendarsAttributes { + calendars_id: number; + displayName?: string; + url?: string; + ctag?: string; + description?: string; + calendarColor?: string; + syncToken?: string; + timezone?: string; + reports?: string; + resourcetype?: string; + caldav_accounts_id?: string; + updated?: string; +} + +export type calendarsPk = "calendars_id"; +export type calendarsId = calendars[calendarsPk]; +export type calendarsOptionalAttributes = "calendars_id" | "displayName" | "url" | "ctag" | "description" | "calendarColor" | "syncToken" | "timezone" | "reports" | "resourcetype" | "caldav_accounts_id" | "updated"; +export type calendarsCreationAttributes = Optional; + +export class calendars extends Model implements calendarsAttributes { + calendars_id!: number; + displayName?: string; + url?: string; + ctag?: string; + description?: string; + calendarColor?: string; + syncToken?: string; + timezone?: string; + reports?: string; + resourcetype?: string; + caldav_accounts_id?: string; + updated?: string; + + + static initModel(sequelize: Sequelize.Sequelize): typeof calendars { + return calendars.init({ + calendars_id: { + autoIncrement: true, + type: DataTypes.BIGINT, + allowNull: false, + primaryKey: true + }, + displayName: { + type: DataTypes.STRING(45), + allowNull: true + }, + url: { + type: DataTypes.STRING(200), + allowNull: true + }, + ctag: { + type: DataTypes.STRING(200), + allowNull: true + }, + description: { + type: DataTypes.STRING(45), + allowNull: true + }, + calendarColor: { + type: DataTypes.STRING(45), + allowNull: true + }, + syncToken: { + type: DataTypes.STRING(200), + allowNull: true + }, + timezone: { + type: DataTypes.STRING(45), + allowNull: true + }, + reports: { + type: DataTypes.STRING(2000), + allowNull: true + }, + resourcetype: { + type: DataTypes.STRING(45), + allowNull: true + }, + caldav_accounts_id: { + type: DataTypes.STRING(45), + allowNull: true + }, + updated: { + type: DataTypes.STRING(45), + allowNull: true + } + }, { + sequelize, + tableName: 'calendars', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "calendars_id" }, + ] + }, + ] + }); + } +} diff --git a/models/custom_filters.ts b/models/custom_filters.ts new file mode 100644 index 0000000..076135f --- /dev/null +++ b/models/custom_filters.ts @@ -0,0 +1,59 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface custom_filtersAttributes { + custom_filters_id: number; + name?: string; + filtervalue?: string; + userid?: string; +} + +export type custom_filtersPk = "custom_filters_id"; +export type custom_filtersId = custom_filters[custom_filtersPk]; +export type custom_filtersOptionalAttributes = "custom_filters_id" | "name" | "filtervalue" | "userid"; +export type custom_filtersCreationAttributes = Optional; + +export class custom_filters extends Model implements custom_filtersAttributes { + custom_filters_id!: number; + name?: string; + filtervalue?: string; + userid?: string; + + + static initModel(sequelize: Sequelize.Sequelize): typeof custom_filters { + return custom_filters.init({ + custom_filters_id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + name: { + type: DataTypes.STRING(100), + allowNull: true + }, + filtervalue: { + type: DataTypes.STRING(1000), + allowNull: true + }, + userid: { + type: DataTypes.STRING(45), + allowNull: true + } + }, { + sequelize, + tableName: 'custom_filters', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "custom_filters_id" }, + ] + }, + ] + }); + } +} diff --git a/models/index.js b/models/index.js new file mode 100644 index 0000000..024200e --- /dev/null +++ b/models/index.js @@ -0,0 +1,43 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const Sequelize = require('sequelize'); +const process = require('process'); +const basename = path.basename(__filename); +const env = process.env.NODE_ENV || 'development'; +const config = require(__dirname + '/../config/config.json')[env]; +const db = {}; + +let sequelize; +if (config.use_env_variable) { + sequelize = new Sequelize(process.env[config.use_env_variable], config); +} else { + sequelize = new Sequelize(config.database, config.username, config.password, config); +} + +fs + .readdirSync(__dirname) + .filter(file => { + return ( + file.indexOf('.') !== 0 && + file !== basename && + file.slice(-3) === '.js' && + file.indexOf('.test.js') === -1 + ); + }) + .forEach(file => { + const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes); + db[model.name] = model; + }); + +Object.keys(db).forEach(modelName => { + if (db[modelName].associate) { + db[modelName].associate(db); + } +}); + +db.sequelize = sequelize; +db.Sequelize = Sequelize; + +module.exports = db; diff --git a/models/init-models.ts b/models/init-models.ts new file mode 100644 index 0000000..81c389e --- /dev/null +++ b/models/init-models.ts @@ -0,0 +1,77 @@ +import type { Sequelize } from "sequelize"; +import { caldav_accounts as _caldav_accounts } from "./caldav_accounts"; +import type { caldav_accountsAttributes, caldav_accountsCreationAttributes } from "./caldav_accounts"; +import { calendar_events as _calendar_events } from "./calendar_events"; +import type { calendar_eventsAttributes, calendar_eventsCreationAttributes } from "./calendar_events"; +import { calendars as _calendars } from "./calendars"; +import type { calendarsAttributes, calendarsCreationAttributes } from "./calendars"; +import { custom_filters as _custom_filters } from "./custom_filters"; +import type { custom_filtersAttributes, custom_filtersCreationAttributes } from "./custom_filters"; +import { labels as _labels } from "./labels"; +import type { labelsAttributes, labelsCreationAttributes } from "./labels"; +import { otp_table as _otp_table } from "./otp_table"; +import type { otp_tableAttributes, otp_tableCreationAttributes } from "./otp_table"; +import { settings as _settings } from "./settings"; +import type { settingsAttributes, settingsCreationAttributes } from "./settings"; +import { ssid_table as _ssid_table } from "./ssid_table"; +import type { ssid_tableAttributes, ssid_tableCreationAttributes } from "./ssid_table"; +import { users as _users } from "./users"; +import type { usersAttributes, usersCreationAttributes } from "./users"; + +export { + _caldav_accounts as caldav_accounts, + _calendar_events as calendar_events, + _calendars as calendars, + _custom_filters as custom_filters, + _labels as labels, + _otp_table as otp_table, + _settings as settings, + _ssid_table as ssid_table, + _users as users, +}; + +export type { + caldav_accountsAttributes, + caldav_accountsCreationAttributes, + calendar_eventsAttributes, + calendar_eventsCreationAttributes, + calendarsAttributes, + calendarsCreationAttributes, + custom_filtersAttributes, + custom_filtersCreationAttributes, + labelsAttributes, + labelsCreationAttributes, + otp_tableAttributes, + otp_tableCreationAttributes, + settingsAttributes, + settingsCreationAttributes, + ssid_tableAttributes, + ssid_tableCreationAttributes, + usersAttributes, + usersCreationAttributes, +}; + +export function initModels(sequelize: Sequelize) { + const caldav_accounts = _caldav_accounts.initModel(sequelize); + const calendar_events = _calendar_events.initModel(sequelize); + const calendars = _calendars.initModel(sequelize); + const custom_filters = _custom_filters.initModel(sequelize); + const labels = _labels.initModel(sequelize); + const otp_table = _otp_table.initModel(sequelize); + const settings = _settings.initModel(sequelize); + const ssid_table = _ssid_table.initModel(sequelize); + const users = _users.initModel(sequelize); + + + return { + caldav_accounts: caldav_accounts, + calendar_events: calendar_events, + calendars: calendars, + custom_filters: custom_filters, + labels: labels, + otp_table: otp_table, + settings: settings, + ssid_table: ssid_table, + users: users, + }; +} diff --git a/models/labels.ts b/models/labels.ts new file mode 100644 index 0000000..b741fe1 --- /dev/null +++ b/models/labels.ts @@ -0,0 +1,59 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface labelsAttributes { + labels_id: number; + name?: string; + colour?: string; + userid?: string; +} + +export type labelsPk = "labels_id"; +export type labelsId = labels[labelsPk]; +export type labelsOptionalAttributes = "labels_id" | "name" | "colour" | "userid"; +export type labelsCreationAttributes = Optional; + +export class labels extends Model implements labelsAttributes { + labels_id!: number; + name?: string; + colour?: string; + userid?: string; + + + static initModel(sequelize: Sequelize.Sequelize): typeof labels { + return labels.init({ + labels_id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + name: { + type: DataTypes.STRING(45), + allowNull: true + }, + colour: { + type: DataTypes.STRING(45), + allowNull: true + }, + userid: { + type: DataTypes.STRING(45), + allowNull: true + } + }, { + sequelize, + tableName: 'labels', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "labels_id" }, + ] + }, + ] + }); + } +} diff --git a/models/otp_table.ts b/models/otp_table.ts new file mode 100644 index 0000000..19f5968 --- /dev/null +++ b/models/otp_table.ts @@ -0,0 +1,71 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface otp_tableAttributes { + otp_table_id: number; + userid?: string; + otp?: string; + created?: string; + type?: string; + reqid?: string; +} + +export type otp_tablePk = "otp_table_id"; +export type otp_tableId = otp_table[otp_tablePk]; +export type otp_tableOptionalAttributes = "otp_table_id" | "userid" | "otp" | "created" | "type" | "reqid"; +export type otp_tableCreationAttributes = Optional; + +export class otp_table extends Model implements otp_tableAttributes { + otp_table_id!: number; + userid?: string; + otp?: string; + created?: string; + type?: string; + reqid?: string; + + + static initModel(sequelize: Sequelize.Sequelize): typeof otp_table { + return otp_table.init({ + otp_table_id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + userid: { + type: DataTypes.STRING(45), + allowNull: true + }, + otp: { + type: DataTypes.STRING(45), + allowNull: true + }, + created: { + type: DataTypes.STRING(45), + allowNull: true + }, + type: { + type: DataTypes.STRING(45), + allowNull: true + }, + reqid: { + type: DataTypes.STRING(2000), + allowNull: true + } + }, { + sequelize, + tableName: 'otp_table', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "otp_table_id" }, + ] + }, + ] + }); + } +} diff --git a/models/session.js b/models/session.js new file mode 100644 index 0000000..e3b9628 --- /dev/null +++ b/models/session.js @@ -0,0 +1,22 @@ +'use strict'; +const { + Model +} = require('sequelize'); +module.exports = (sequelize, DataTypes) => { + class Session extends Model { + static associate(models) { + // define association here + } + } + Session.init({ + id: DataTypes.UUID, + expires:DataTypes.DATE, + timestamp: DataTypes.DATE, + session_token: DataTypes.STRING, + user_id: DataTypes.UUID + }, { + sequelize, + modelName: 'session', + }); + return Session; +}; \ No newline at end of file diff --git a/models/settings.ts b/models/settings.ts new file mode 100644 index 0000000..b09dfdc --- /dev/null +++ b/models/settings.ts @@ -0,0 +1,65 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface settingsAttributes { + settings_id: number; + name?: string; + userid?: string; + global?: string; + value?: string; +} + +export type settingsPk = "settings_id"; +export type settingsId = settings[settingsPk]; +export type settingsOptionalAttributes = "settings_id" | "name" | "userid" | "global" | "value"; +export type settingsCreationAttributes = Optional; + +export class settings extends Model implements settingsAttributes { + settings_id!: number; + name?: string; + userid?: string; + global?: string; + value?: string; + + + static initModel(sequelize: Sequelize.Sequelize): typeof settings { + return settings.init({ + settings_id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + name: { + type: DataTypes.STRING(200), + allowNull: true + }, + userid: { + type: DataTypes.STRING(45), + allowNull: true + }, + global: { + type: DataTypes.STRING(45), + allowNull: true + }, + value: { + type: DataTypes.STRING(1000), + allowNull: true + } + }, { + sequelize, + tableName: 'settings', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "settings_id" }, + ] + }, + ] + }); + } +} diff --git a/models/ssid_table.ts b/models/ssid_table.ts new file mode 100644 index 0000000..1c46f97 --- /dev/null +++ b/models/ssid_table.ts @@ -0,0 +1,59 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface ssid_tableAttributes { + ssid_table_id: number; + userhash?: string; + ssid?: string; + created?: string; +} + +export type ssid_tablePk = "ssid_table_id"; +export type ssid_tableId = ssid_table[ssid_tablePk]; +export type ssid_tableOptionalAttributes = "ssid_table_id" | "userhash" | "ssid" | "created"; +export type ssid_tableCreationAttributes = Optional; + +export class ssid_table extends Model implements ssid_tableAttributes { + ssid_table_id!: number; + userhash?: string; + ssid?: string; + created?: string; + + + static initModel(sequelize: Sequelize.Sequelize): typeof ssid_table { + return ssid_table.init({ + ssid_table_id: { + autoIncrement: true, + type: DataTypes.INTEGER, + allowNull: false, + primaryKey: true + }, + userhash: { + type: DataTypes.STRING(1000), + allowNull: true + }, + ssid: { + type: DataTypes.STRING(1000), + allowNull: true + }, + created: { + type: DataTypes.STRING(45), + allowNull: true + } + }, { + sequelize, + tableName: 'ssid_table', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "ssid_table_id" }, + ] + }, + ] + }); + } +} diff --git a/models/users.ts b/models/users.ts new file mode 100644 index 0000000..bebeeb1 --- /dev/null +++ b/models/users.ts @@ -0,0 +1,119 @@ +import * as Sequelize from 'sequelize'; +import { DataTypes, Model, Optional } from 'sequelize'; + +export interface usersAttributes { + users_id: number; + username?: string; + email?: string; + password?: string; + created?: string; + level?: string; + userhash?: string; + mobile?: string; + id?: number; + expires?:Date; + session_token?:string; + name?:string; + email_verified?:string; + image?:string + +} + +export type usersPk = "users_id"; +export type usersId = users[usersPk]; +export type usersOptionalAttributes = "users_id" | "username" | "email" | "password" | "created" | "level" | "userhash" | "mobile"; +export type usersCreationAttributes = Optional; + +export class users extends Model implements usersAttributes { + users_id!: number; + username?: string; + email?: string; + password?: string; + created?: string; + level?: string; + userhash?: string; + mobile?: string; + id?: number; + expires?:Date; + session_token?:string; + name?:string; + email_verified?:string; + image?:string + + + static initModel(sequelize: Sequelize.Sequelize): typeof users { + return users.init({ + users_id: { + autoIncrement: true, + type: DataTypes.INTEGER, + primaryKey: true + }, + username: { + type: DataTypes.STRING(45), + allowNull: true + }, + email: { + type: DataTypes.STRING(45), + allowNull: true + }, + password: { + type: DataTypes.STRING(1000), + allowNull: true + }, + created: { + type: DataTypes.STRING(45), + allowNull: true + }, + level: { + type: DataTypes.STRING(45), + allowNull: true + }, + userhash: { + type: DataTypes.STRING(1000), + allowNull: true + }, + mobile: { + type: DataTypes.STRING(45), + allowNull: true + }, + id:{ + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + + }, + expires:{ + type: Sequelize.DataTypes.DATE, + + }, + session_token:{ + type: Sequelize.DataTypes.STRING, + unique: "sessionToken", + }, + name:{ + type: Sequelize.DataTypes.STRING + }, + email_verified:{ + type: Sequelize.DataTypes.STRING, + }, + image:{ + type: Sequelize.DataTypes.STRING, + + } + + }, { + sequelize, + tableName: 'users', + timestamps: false, + indexes: [ + { + name: "PRIMARY", + unique: true, + using: "BTREE", + fields: [ + { name: "users_id" }, + ] + }, + ] + }); + } +} diff --git a/package-lock.json b/package-lock.json index a53f3fb..488e56c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,14 @@ { "name": "manage-my-damn-life-nextjs", - "version": "0.2.0", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "manage-my-damn-life-nextjs", - "version": "0.2.0", + "version": "0.3.0", "dependencies": { + "@auth/sequelize-adapter": "1.0.1", "@babel/core": "7.21.8", "@emotion/react": "11.10.6", "@emotion/styled": "11.10.6", @@ -39,11 +40,13 @@ "ical.js": "1.5.0", "js-base64": "3.7.5", "js-cookie": "3.0.1", + "keycloak-js": "22.0.1", "lodash": "4.17.21", "moment": "2.29.4", "mysql": "2.18.1", "mysql2": "3.4.0", "next": "13.2.4", + "next-auth": "4.22.3", "nextjs-progressbar": "0.0.16", "nodemailer": "6.9.1", "popper.js": "1.16.1", @@ -98,6 +101,58 @@ "node": ">=6.0.0" } }, + "node_modules/@auth/core": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.8.3.tgz", + "integrity": "sha512-lbpMRk36uhBrfJFL77YEPu9tOLI0XtcjZ4nYBzebcadliHeQITIilQGLbZ107hKMI0rfX3tOEbyybgdOtJHjxw==", + "dependencies": { + "@panva/hkdf": "^1.0.4", + "cookie": "0.5.0", + "jose": "^4.11.1", + "oauth4webapi": "^2.0.6", + "preact": "10.11.3", + "preact-render-to-string": "5.2.3" + }, + "peerDependencies": { + "nodemailer": "^6.8.0" + }, + "peerDependenciesMeta": { + "nodemailer": { + "optional": true + } + } + }, + "node_modules/@auth/core/node_modules/preact": { + "version": "10.11.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz", + "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/@auth/core/node_modules/preact-render-to-string": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz", + "integrity": "sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==", + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, + "node_modules/@auth/sequelize-adapter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@auth/sequelize-adapter/-/sequelize-adapter-1.0.1.tgz", + "integrity": "sha512-BePsH+pKOb08tHFNY4Q3/S9jLWdPPKvlJuITMGAdSC/rUgE6x3lk1BYsEBgVZGwcS0Fczlv/xdjTcmF8/kh5gg==", + "dependencies": { + "@auth/core": "0.8.3" + }, + "peerDependencies": { + "sequelize": "^6.6.5" + } + }, "node_modules/@babel/code-frame": { "version": "7.22.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", @@ -2915,6 +2970,14 @@ "node": ">= 8" } }, + "node_modules/@panva/hkdf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz", + "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/@pkgr/utils": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", @@ -3665,7 +3728,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -4173,6 +4235,14 @@ "version": "1.9.0", "license": "MIT" }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/core-js-compat": { "version": "3.31.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.31.1.tgz", @@ -7258,6 +7328,14 @@ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, + "node_modules/jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-base64": { "version": "3.7.5", "license": "BSD-3-Clause" @@ -7288,6 +7366,11 @@ "node": ">=12" } }, + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, "node_modules/js-tokens": { "version": "4.0.0", "license": "MIT" @@ -7387,6 +7470,15 @@ "node": ">=4.0" } }, + "node_modules/keycloak-js": { + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-22.0.1.tgz", + "integrity": "sha512-5cwOzMTMW2HuKGaIHv50BJHz2o8ID+YgzaaXKNwOk0XqD6ZOPD/jQXvqTz+Z8ID5cP46zVWnNiTouFK41NbPOQ==", + "dependencies": { + "base64-js": "^1.5.1", + "js-sha256": "^0.9.0" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -8033,6 +8125,33 @@ } } }, + "node_modules/next-auth": { + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.22.3.tgz", + "integrity": "sha512-XAgy9xV3J2eJOXrQhmxdjV6MLM29ibm6WtMXc3KY6IPZeApf+SuBuPvlqCUfbu5YsAzlg9WSw6u01dChTfeZOA==", + "dependencies": { + "@babel/runtime": "^7.20.13", + "@panva/hkdf": "^1.0.2", + "cookie": "^0.5.0", + "jose": "^4.11.4", + "oauth": "^0.9.15", + "openid-client": "^5.4.0", + "preact": "^10.6.3", + "preact-render-to-string": "^5.1.19", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "next": "^12.2.5 || ^13", + "nodemailer": "^6.6.5", + "react": "^17.0.2 || ^18", + "react-dom": "^17.0.2 || ^18" + }, + "peerDependenciesMeta": { + "nodemailer": { + "optional": true + } + } + }, "node_modules/next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -8152,6 +8271,19 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + }, + "node_modules/oauth4webapi": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.3.0.tgz", + "integrity": "sha512-JGkb5doGrwzVDuHwgrR4nHJayzN4h59VCed6EW8Tql6iHDfZIabCJvg6wtbn5q6pyB2hZruI3b77Nudvq7NmvA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/object-assign": { "version": "4.1.1", "license": "MIT", @@ -8159,6 +8291,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", @@ -8256,6 +8396,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oidc-token-hash": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", + "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==", + "engines": { + "node": "^10.13.0 || >=12.0.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8297,6 +8445,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/openid-client": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.4.3.tgz", + "integrity": "sha512-sVQOvjsT/sbSfYsQI/9liWQGVZH/Pp3rrtlGEwgk/bbHfrUDZ24DN57lAagIwFtuEu+FM9Ev7r85s8S/yPjimQ==", + "dependencies": { + "jose": "^4.14.4", + "lru-cache": "^6.0.0", + "object-hash": "^2.2.0", + "oidc-token-hash": "^5.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/openid-client/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/openid-client/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -8996,6 +9174,17 @@ "url": "https://opencollective.com/preact" } }, + "node_modules/preact-render-to-string": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz", + "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==", + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -9017,6 +9206,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" + }, "node_modules/process-nextick-args": { "version": "2.0.1", "license": "MIT" diff --git a/package.json b/package.json index 938ca18..64f8acd 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,18 @@ { "name": "manage-my-damn-life-nextjs", - "version": "0.2.0", + "version": "0.3.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", + "migrate": "npx sequelize-cli db:migrate --env local", + "undo-migrate": "npx sequelize-cli db:migrate:undo --env local", "cypress": "cypress open" }, "dependencies": { + "@auth/sequelize-adapter": "1.0.1", "@babel/core": "7.21.8", "@emotion/react": "11.10.6", "@emotion/styled": "11.10.6", @@ -41,11 +44,13 @@ "ical.js": "1.5.0", "js-base64": "3.7.5", "js-cookie": "3.0.1", + "keycloak-js": "22.0.1", "lodash": "4.17.21", "moment": "2.29.4", "mysql": "2.18.1", "mysql2": "3.4.0", "next": "13.2.4", + "next-auth": "4.22.3", "nextjs-progressbar": "0.0.16", "nodemailer": "6.9.1", "popper.js": "1.16.1", diff --git a/src/components/Home/HomeTasks/HomeTasks.tsx b/src/components/Home/HomeTasks/HomeTasks.tsx index ec66f06..a53ee7e 100644 --- a/src/components/Home/HomeTasks/HomeTasks.tsx +++ b/src/components/Home/HomeTasks/HomeTasks.tsx @@ -1,5 +1,4 @@ import { getI18nObject } from "@/helpers/frontend/general"; -import { withRouter } from "next/router"; import React, { FC, ReactElement, useEffect, useState } from 'react'; import TaskList from "../../tasks/TaskList"; import { getTodaysDateUnixTimeStamp, varNotEmpty } from "@/helpers/general"; @@ -7,6 +6,7 @@ import { MYDAY_LABEL } from "@/config/constants"; import Form from 'react-bootstrap/Form'; import { refreshMenuOptionsFromServer } from "./HomeTasksFunctions"; import { isValidFilter } from "@/helpers/frontend/filters"; +import * as _ from 'lodash' interface homeTasksPropsInterface { router: object @@ -52,7 +52,11 @@ function HomeTasks(props:homeTasksPropsInterface) { useEffect( () => { const refreshMenuOptions = async () =>{ const newMenuOptions = await refreshMenuOptionsFromServer(menuOptions) - setMenuOptions(newMenuOptions) + //console.log(menuOptions, newMenuOptions) + if(_.isEqual(menuOptions, newMenuOptions) ==false){ + setMenuOptions(newMenuOptions) + + } } refreshMenuOptions() }, [updated, menuOptions]) diff --git a/src/components/LabelManager.js b/src/components/LabelManager.js index 341f1ba..7e03590 100644 --- a/src/components/LabelManager.js +++ b/src/components/LabelManager.js @@ -157,20 +157,13 @@ class LabelManager extends Component{ }else{ var message= getMessageFromAPIResponse(body) + console.error("getLabelsFromServer", message, body) + if(message!=null) { - if(message=="PLEASE_LOGIN") + if(message!=="PLEASE_LOGIN") { - // Login required - var redirectURL="/login" - if(window!=undefined) - { - - - redirectURL +="?redirect="+window.location.pathname - } - this.props.router.push(redirectURL) - + toast.error(this.i18next.t(message)) } } diff --git a/src/components/common/AppBarGeneric.js b/src/components/common/AppBar/AppBarGenericClass.js similarity index 89% rename from src/components/common/AppBarGeneric.js rename to src/components/common/AppBar/AppBarGenericClass.js index 43c5d01..c2d3286 100644 --- a/src/components/common/AppBarGeneric.js +++ b/src/components/common/AppBar/AppBarGenericClass.js @@ -11,18 +11,21 @@ import { getI18nObject } from "@/helpers/frontend/general"; import { AiOutlineSetting, AiOutlineUser } from "react-icons/ai"; import {IoSyncCircleOutline} from "react-icons/io5/index"; import { BiLogOut } from "react-icons/bi"; -import { logoutUser } from "@/helpers/frontend/user"; +import { logoutUser, logoutUser_withRedirect } from "@/helpers/frontend/user"; import Link from "next/link"; import { getSyncTimeout } from "@/helpers/frontend/settings"; import { toast } from "react-toastify"; import Dropdown from 'react-bootstrap/Dropdown'; import { getUserNameFromCookie } from "@/helpers/frontend/cookies"; import Image from "next/image"; -class AppBarGeneric extends Component { +import { signOut, useSession } from "next-auth/react"; +import { getNextAuthSessionData, nextAuthEnabled } from "@/helpers/thirdparty/nextAuth"; + +class AppBarGeneric_ClassComponent extends Component { constructor(props) { super(props) - this.state = { isSyncing: this.props.isSyncing, username: "" } + this.state = { isSyncing: this.props.isSyncing, username: "", } this.i18next = getI18nObject() this.logoClicked = this.logoClicked.bind(this) this.taskViewClicked = this.taskViewClicked.bind(this) @@ -40,10 +43,31 @@ componentDidMount(){ setInterval(() => { //context.syncButtonClicked() //toast.info("syncing") - console.log("getSyncTimeout", getSyncTimeout()) }, getSyncTimeout()) - this.setState({username: getUserNameFromCookie()}) + let username="" + try{ + if(nextAuthEnabled()){ + if(this.props.session) + { + + const { data: session, status } = this.props.session + if(status!="loading"){ + username = session.user.name + + }else{ + + } + } + }else{ + + username = getUserNameFromCookie() + } + + }catch(e){ + + } + this.setState({username: username}) } @@ -79,8 +103,7 @@ async syncButtonClicked() { } logOutClicked() { - logoutUser() - this.props.router.push("/login") + logoutUser_withRedirect(this.props.router) } settingsClicked() { @@ -89,7 +112,6 @@ async syncButtonClicked() { manageFilterClicked() { this.props.router.push("/filters/manage") - } labelManageClicked(){ this.props.router.push("/labels/manage") @@ -185,4 +207,4 @@ async syncButtonClicked() { } } -export default withRouter(AppBarGeneric) \ No newline at end of file +export default withRouter(AppBarGeneric_ClassComponent) \ No newline at end of file diff --git a/src/components/common/AppBar/index.tsx b/src/components/common/AppBar/index.tsx new file mode 100644 index 0000000..54d301e --- /dev/null +++ b/src/components/common/AppBar/index.tsx @@ -0,0 +1,16 @@ +import { useSession } from "next-auth/react"; +import AppBarGeneric_ClassComponent from "./AppBarGenericClass"; +import { useRouter } from "next/router"; + +interface propsType{ + isSyncing?: boolean, + onSynComplete?: Function +} +const AppBarGeneric= ({isSyncing, onSynComplete}:propsType) =>{ + + const session = useSession() + const router = useRouter() + return +} + +export default AppBarGeneric \ No newline at end of file diff --git a/src/components/common/AppBarGeneric copy.js b/src/components/common/AppBarGeneric copy.js deleted file mode 100644 index af5364f..0000000 --- a/src/components/common/AppBarGeneric copy.js +++ /dev/null @@ -1,89 +0,0 @@ -import { PRIMARY_COLOUR } from "@/config/style" -import Row from 'react-bootstrap/Row'; -import Col from "react-bootstrap/Col"; -import { useRouter, withRouter } from "next/router"; -import { Button, Spinner } from "react-bootstrap"; -import React, { Component, useState } from 'react'; -import { fetchLatestEvents, makeSyncRequest } from "@/helpers/frontend/sync"; -import Navbar from 'react-bootstrap/Navbar'; -import Nav from 'react-bootstrap/Nav'; -class AppBarGeneric extends Component { - - constructor(props) { - super(props) - this.state = { isSyncing: this.props.isSyncing } - this.logoClicked = this.logoClicked.bind(this) - this.taskViewClicked = this.taskViewClicked.bind(this) - this.syncButtonClicked = this.syncButtonClicked.bind(this) - - } -componentDidMount(){ - this.setState({isSyncing: this.props.isSyncing}) -} - - -componentDidUpdate(prevProps, prevState) { - - if (this.props.isSyncing !== prevProps.isSyncing) { - - this.setState({isSyncing: this.props.isSyncing}) - } - - -} - - -async syncButtonClicked() { - this.setState({isSyncing: true}) - - //Make a refresh Request for all caldav accounts. - await fetchLatestEvents() - this.setState({isSyncing: false}) - if(this.props.onSynComplete!=null) - { - this.props.onSynComplete() - } - - } - logoClicked() { - this.props.router.push("/") - } - taskViewClicked() { - this.props.router.push('/tasks/list') - } - render() { - var syncButton = this.state.isSyncing ? () : () - return ( - - - -

- - - - ) - } -} - -export default withRouter(AppBarGeneric) \ No newline at end of file diff --git a/src/components/common/GenericLists.js b/src/components/common/GenericLists.js index c525c65..f6bbb08 100644 --- a/src/components/common/GenericLists.js +++ b/src/components/common/GenericLists.js @@ -97,19 +97,21 @@ class GenericLists extends Component{ }else{ var message= getMessageFromAPIResponse(body) + console.error("generateLabelList", message, body) + if(message!=null) { if(message=="PLEASE_LOGIN") { // Login required - var redirectURL="/login" - if(window!=undefined) - { + // var redirectURL="/login" + // if(window!=undefined) + // { - redirectURL +="?redirect="+window.location.pathname - } - this.props.router.push(redirectURL) + // redirectURL +="?redirect="+window.location.pathname + // } + // this.props.router.push(redirectURL) } diff --git a/src/components/common/calendars/ShowCalendarList.js b/src/components/common/calendars/ShowCalendarList.js index f89a055..aa07f2f 100644 --- a/src/components/common/calendars/ShowCalendarList.js +++ b/src/components/common/calendars/ShowCalendarList.js @@ -97,25 +97,34 @@ class ShowCalendarList extends Component{ toast.error(this.i18.t("ERROR_GENERIC")) }else{ var message= getMessageFromAPIResponse(caldav_accounts) + console.error("getCaldavAccountsfromDB", message, caldav_accounts) + if(message!=null) { - if(message=="PLEASE_LOGIN") + + if(message!=="PLEASE_LOGIN") { - // Login required - var redirectURL="/login" - if(window!=undefined) - { + toast.error(this.i18.t(message)) + } + // if(message=="PLEASE_LOGIN") + // { + + // // Login required + // var redirectURL="/login" + // if(window!=undefined) + // { - redirectURL +="?redirect="+window.location.pathname - } - this.props.router.push(redirectURL) + // redirectURL +="?redirect="+window.location.pathname + // } + // this.props.router.push(redirectURL) - }else{ - toast.error(this.i18.t(message)) - } + // }else{ + // toast.error(this.i18.t(message)) + + // } } else { diff --git a/src/components/common/calendars/caldavAccounts/CaldavAccounts.js b/src/components/common/calendars/caldavAccounts/CaldavAccounts.js index 0138328..a9dcd7d 100644 --- a/src/components/common/calendars/caldavAccounts/CaldavAccounts.js +++ b/src/components/common/calendars/caldavAccounts/CaldavAccounts.js @@ -28,7 +28,6 @@ export default class CaldavAccounts extends Component{ this.getCaldavAccountsfromDB = this.getCaldavAccountsfromDB.bind(this) this.showAddAccountModal = this.showAddAccountModal.bind(this) - this.getCaldavAccountsfromDB() this.onAccountAddSuccess = this.onAccountAddSuccess.bind(this) this.syncButtonClicked = this.syncButtonClicked.bind(this) this.onAddAccountDismissed = this.onAddAccountDismissed.bind(this) @@ -42,6 +41,8 @@ export default class CaldavAccounts extends Component{ } componentDidMount(){ + this.getCaldavAccountsfromDB() + if(window!=undefined){ const queryString = window.location.search; const params = new URLSearchParams(queryString); diff --git a/src/components/filters/AddFilter.js b/src/components/filters/AddFilter.js index 9be009e..f2a2db3 100644 --- a/src/components/filters/AddFilter.js +++ b/src/components/filters/AddFilter.js @@ -1,4 +1,3 @@ -import AppBarGeneric from "@/components/common/AppBarGeneric" import { SECONDARY_COLOUR } from "@/config/style" import Head from "next/head" import { withRouter } from "next/router" diff --git a/src/components/filters/FilterList.js b/src/components/filters/FilterList.js index 8402a96..169f61a 100644 --- a/src/components/filters/FilterList.js +++ b/src/components/filters/FilterList.js @@ -38,25 +38,33 @@ class FilterList extends Component { toast.error(this.i18next.t("ERROR_GENERIC")) }else{ var message= getMessageFromAPIResponse(filtersFromServer) + console.error("generateList", message, filtersFromServer) + if(message!=null) { - if(message=="PLEASE_LOGIN") + if(message!="PLEASE_LOGIN") { - // Login required - var redirectURL="/login" - if(window!=undefined) - { + // toast.error(this.i18next.t(message)) + } - redirectURL +="?redirect="+window.location.pathname - } - this.props.router.push(redirectURL) + // if(message=="PLEASE_LOGIN") + // { + // // Login required + // var redirectURL="/login" + // if(window!=undefined) + // { - }else{ - toast.error(this.i18next.t(message)) + // redirectURL +="?redirect="+window.location.pathname + // } + // this.props.router.push(redirectURL) - } + + // }else{ + // toast.error(this.i18next.t(message)) + + // } } else { diff --git a/src/components/fullcalendar/DashboardView.js b/src/components/fullcalendar/DashboardView.js index 2f6cb99..db2ab70 100644 --- a/src/components/fullcalendar/DashboardView.js +++ b/src/components/fullcalendar/DashboardView.js @@ -80,25 +80,31 @@ class DashboardView extends Component { }else{ var message =getMessageFromAPIResponse(caldav_accounts) + console.error("getCaldavAccountsfromDB", message, caldav_accounts) + if(message!=null) { - if(message=="PLEASE_LOGIN") + if(message!=="PLEASE_LOGIN") { - // Login required - var redirectURL="/login" - if(window!=undefined) - { + toast.error(this.i18next.t(message)) + } + // if(message=="PLEASE_LOGIN") + // { + // // Login required + // var redirectURL="/login" + // if(window!=undefined) + // { - redirectURL +="?redirect="+window.location.pathname - } - this.props.router.push(redirectURL) + // redirectURL +="?redirect="+window.location.pathname + // } + // this.props.router.push(redirectURL) - }else{ - toast.error(this.i18next.t(message)) + // }else{ + // toast.error(this.i18next.t(message)) - } + // } } else { @@ -198,7 +204,7 @@ class DashboardView extends Component { } //Calculate delta in ms var eventData = this.state.allEvents[newID] - if (this.state.allEvents[newID].type != "VTODO" && this.state.allEvents[newID].type != "VTIMEZONE" && varNotEmpty(this.state.allEvents[newID])) { + if (this.state.allEvents && this.state.allEvents[newID] && this.state.allEvents[newID].type != "VTODO" && this.state.allEvents[newID].type != "VTIMEZONE" && varNotEmpty(this.state.allEvents[newID])) { var delta = e.delta.milliseconds + (e.delta.days * 86400 * 1000) + (e.delta.months * 30 * 86400 * 1000) + (e.delta.years * 365 * 86400 * 1000) //console.log("delta", delta) @@ -248,7 +254,7 @@ class DashboardView extends Component { } async eventResize(e) { - //console.log("eventResize", e) + console.log("eventResize", this.state.allEvents[e.event.id]) var newID = e.event.id if (varNotEmpty(this.state.allEvents[e.event.id]) == false) { //Probably a recurring event. Get ID from map. @@ -256,8 +262,8 @@ class DashboardView extends Component { } //Calculate delta in ms - var eventData = this.state.allEvents[newID] - if (this.state.allEvents[newID].type != "VTODO" && this.state.allEvents[newID].type != "VTIMEZONE" && varNotEmpty(this.state.allEvents[newID])) { + var eventData = _.cloneDeep(this.state.allEvents[newID]) + if (this.state.allEvents && this.state.allEvents[newID] && this.state.allEvents[newID].type != "VTODO" && this.state.allEvents[newID].type != "VTIMEZONE" && varNotEmpty(this.state.allEvents[newID])) { var delta = e.endDelta.milliseconds + (e.endDelta.days * 86400 * 1000) + (e.endDelta.months * 30 * 86400 * 1000) + (e.endDelta.years * 365 * 86400 * 1000) //console.log("delta", delta) @@ -294,6 +300,8 @@ class DashboardView extends Component { toast.error((this.i18next.t("ERROR_GENERIC"))) } + }else{ + console.log("oaspdaosdpoaspdoaspdoasd") } @@ -325,7 +333,6 @@ class DashboardView extends Component { async addEventsToCalendar(allEvents){ var finalEvents = [] - if (isValidResultArray(allEvents.data.message)) { for (let i = 0; i < allEvents.data.message.length; i++) { @@ -459,7 +466,13 @@ class DashboardView extends Component { } */ - //this.state.allEvents[data.uid] = { data: data, event: allEvents.data.message[i].events[j] } + this.setState((prevState, props) => { + var newAllEvents = _.cloneDeep(prevState.allEvents) + newAllEvents[data.uid] = { data: data, event: allEvents.data.message[i].events[j] } + return({allEvents: newAllEvents}) + + }) + // this.state.allEvents[data.uid] = { data: data, event: allEvents.data.message[i].events[j] } } else if (event.type == "VTODO" && this.state.showTasksChecked==true) { @@ -527,7 +540,13 @@ class DashboardView extends Component { } } - + this.setState((prevState, props) => { + var newAllEvents = _.cloneDeep(prevState.allEvents) + newAllEvents[data.uid] = { data: data, event: allEvents.data.message[i].events[j] } + return({allEvents: newAllEvents}) + + }) + } } } diff --git a/src/pages/calendar/view.js b/src/components/page/CalendarViewPage/CalendarView.js similarity index 93% rename from src/pages/calendar/view.js rename to src/components/page/CalendarViewPage/CalendarView.js index b754132..c50dcb8 100644 --- a/src/pages/calendar/view.js +++ b/src/components/page/CalendarViewPage/CalendarView.js @@ -1,8 +1,9 @@ -import AppBarGeneric from "@/components/common/AppBarGeneric"; +import AppBarGeneric from "@/components/common/AppBar"; import DashboardView from "@/components/fullcalendar/DashboardView"; import { getI18nObject } from "@/helpers/frontend/general"; +import { useSession } from "next-auth/react"; import Head from "next/head"; -import { withRouter } from "next/router"; +import { useRouter, withRouter } from "next/router"; import { Component } from "react"; import "react-datetime/css/react-datetime.css"; diff --git a/src/components/page/CombinedView.js b/src/components/page/CombinedView.js index 1042f30..4ab2b25 100644 --- a/src/components/page/CombinedView.js +++ b/src/components/page/CombinedView.js @@ -1,6 +1,3 @@ -import Head from 'next/head' -import TaskList from '@/components/tasks/TaskList' -import AppBarGeneric from '@/components/common/AppBarGeneric' import { Col, Row } from 'react-bootstrap' import { getTodaysDateUnixTimeStamp, varNotEmpty } from '@/helpers/general' import DashboardView from '@/components/fullcalendar/DashboardView' @@ -88,6 +85,7 @@ export default class CombinedView extends Component { render(){ var borderLeft = this.state.showListColumn ? '3px solid ' + SECONDARY_COLOUR : "" var leftColumnMatter = ( <> + {/* diff --git a/src/pages/filters/manage.js b/src/components/page/ManageFiltersPage/ManageFilters.js similarity index 87% rename from src/pages/filters/manage.js rename to src/components/page/ManageFiltersPage/ManageFilters.js index 4fd8fb9..3d8b971 100644 --- a/src/pages/filters/manage.js +++ b/src/components/page/ManageFiltersPage/ManageFilters.js @@ -1,4 +1,4 @@ -import AppBarGeneric from "@/components/common/AppBarGeneric" +import AppBarGeneric from "@/components/common/AppBar" import { Loading } from "@/components/common/Loading" import AddFilter from "@/components/filters/AddFilter" import { Toastify } from "@/components/Generic" @@ -8,8 +8,9 @@ import { filtertoWords, getFiltersFromServer } from "@/helpers/frontend/filters" import { getI18nObject } from "@/helpers/frontend/general" import { getMessageFromAPIResponse } from "@/helpers/frontend/response" import { dateTimeReviver } from "@/helpers/general" +import { useSession } from "next-auth/react" import Head from "next/head" -import { withRouter } from "next/router" +import { useRouter, withRouter } from "next/router" import { Component } from "react" import { Col, Row } from "react-bootstrap" import Button from "react-bootstrap/Button" @@ -71,25 +72,32 @@ class ManageFilters extends Component{ toast.error(this.i18next.t("ERROR_GENERIC")) }else{ var message= getMessageFromAPIResponse(filtersFromServer) + console.error("getAllTodosFromServer", message, filtersFromServer) + if(message!=null) { - if(message=="PLEASE_LOGIN") + if(message!=="PLEASE_LOGIN") { - // Login required - var redirectURL="/login" - if(window!=undefined) - { + toast.error(this.i18next.t(message)) + } + // if(message=="PLEASE_LOGIN") + // { + // // Login required + // var redirectURL="/login" + // if(window!=undefined) + // { - redirectURL +="?redirect="+window.location.pathname - } - this.props.router.push(redirectURL) + // redirectURL +="?redirect="+window.location.pathname + // } + // this.props.router.push(redirectURL) - }else{ - toast.error(this.i18next.t(message)) - } + // }else{ + // toast.error(this.i18next.t(message)) + + // } } else { @@ -168,7 +176,7 @@ class ManageFilters extends Component{ - +

{this.i18next.t("MANAGE_FILTERS")}

{this.i18next.t("MANAGE_FILTERS_DESC")}

@@ -185,5 +193,6 @@ class ManageFilters extends Component{ } } + export default withRouter(ManageFilters) diff --git a/src/pages/labels/manage.js b/src/components/page/MangerLabelsPage/ManageLabels.js similarity index 84% rename from src/pages/labels/manage.js rename to src/components/page/MangerLabelsPage/ManageLabels.js index 0599afc..b872bcb 100644 --- a/src/pages/labels/manage.js +++ b/src/components/page/MangerLabelsPage/ManageLabels.js @@ -1,13 +1,14 @@ import Head from 'next/head' import Container from 'react-bootstrap/Container'; -import AppBarGeneric from "@/components/common/AppBarGeneric" +import AppBarGeneric from "@/components/common/AppBar" import CaldavAccounts from '@/components/common/calendars/caldavAccounts/CaldavAccounts' import LabelManager from '@/components/LabelManager'; import { makeUpdateLabelRequest } from '@/helpers/frontend/labels'; import { getAuthenticationHeadersforUser } from '@/helpers/frontend/user'; import { getI18nObject } from '@/helpers/frontend/general'; +import { withRouter } from 'next/router'; -export default function ManageLables({reply}) { +function ManageLabels() { var i18next = getI18nObject() return ( @@ -28,3 +29,5 @@ export default function ManageLables({reply}) { ) } +export default withRouter(ManageLabels) + diff --git a/src/pages/accounts/settings.js b/src/components/page/SettingsPage/SettingsPage.js similarity index 95% rename from src/pages/accounts/settings.js rename to src/components/page/SettingsPage/SettingsPage.js index f60515f..59d2e85 100644 --- a/src/pages/accounts/settings.js +++ b/src/components/page/SettingsPage/SettingsPage.js @@ -1,13 +1,11 @@ -import AppBarGeneric from "@/components/common/AppBarGeneric"; +import AppBarGeneric from "@/components/common/AppBar"; import { Loading } from "@/components/common/Loading"; import { displayErrorMessageFromAPIResponse, getI18nObject } from "@/helpers/frontend/general"; import Head from "next/head"; -import { Col, Container, ProgressBar, Row } from "react-bootstrap"; -import Placeholder from 'react-bootstrap/Placeholder'; +import { Col, Container, Row } from "react-bootstrap"; const { withRouter } = require("next/router"); const { Component } = require("react"); -import Card from 'react-bootstrap/Card'; -import { getAuthenticationHeadersforUser } from "@/helpers/frontend/user"; +import { getAuthenticationHeadersforUser, logoutUser, logoutUser_withRedirect } from "@/helpers/frontend/user"; import { getAPIURL, isValidResultArray, logVar, varNotEmpty } from "@/helpers/general"; import { BACKGROUND_GRAY } from "@/config/style"; import moment from "moment"; @@ -19,7 +17,8 @@ import Button from "react-bootstrap/Button"; import DefaultCalendarViewSelect from "@/components/accounts/DefaultCalendarViewSelect"; import { VERSION_NUMBER } from "@/config/constants"; import { setDefaultCalendarID } from "@/helpers/frontend/cookies"; -class Settings extends Component { +import { getMessageFromAPIResponse } from "@/helpers/frontend/response"; +class SettingsPage extends Component { constructor(props) { super(props) @@ -84,8 +83,11 @@ class Settings extends Component { } }else{ - console.log(body) - toast.error(this.state.i18next.t("ERROR_GETTING_SETTINGS")) + var message = getMessageFromAPIResponse(body) + console.error("getAllUserSettings", message, body) + // if(message==="PLEASE_LOGIN"){ + // logoutUser_withRedirect(this.props.router) + // } } }).catch(e =>{ @@ -166,7 +168,7 @@ class Settings extends Component { } } else { - toast.error(this.i18next.t("ERROR_GENERIC")) + console.error(this.i18next.t("ERROR_GENERIC"), body) } @@ -394,4 +396,4 @@ class Settings extends Component { } -export default withRouter(Settings) +export default withRouter(SettingsPage) diff --git a/src/pages/tasks/list.js b/src/components/page/TaskViewPage/TaskViewList.js similarity index 99% rename from src/pages/tasks/list.js rename to src/components/page/TaskViewPage/TaskViewList.js index e79abb8..c04dad0 100644 --- a/src/pages/tasks/list.js +++ b/src/components/page/TaskViewPage/TaskViewList.js @@ -1,6 +1,6 @@ import Head from 'next/head' import TaskList from '@/components/tasks/TaskList' -import AppBarGeneric from '@/components/common/AppBarGeneric' +import AppBarGeneric from '@/components/common/AppBar' import '@/../bootstrap/dist/css/bootstrap.min.css' import GenericLists from '@/components/common/GenericLists' import { Component } from 'react' diff --git a/src/components/tasks/TaskList.js b/src/components/tasks/TaskList.js index 8d6c00a..9317a1b 100644 --- a/src/components/tasks/TaskList.js +++ b/src/components/tasks/TaskList.js @@ -109,29 +109,37 @@ import { getAPIURL, logVar } from '@/helpers/general'; toast.error(this.i18next.t("ERROR_GENERIC")) }else{ var message= getMessageFromAPIResponse(responseFromServer) + console.error("getCaldavAccountsfromDB", message, responseFromServer) + if(message!=null) { - if(message=="PLEASE_LOGIN") + if(message!="PLEASE_LOGIN") { - // Login required - var redirectURL="/login" - if(window!=undefined) - { + toast.error(this.i18next.t(message)) + } - redirectURL +="?redirect="+window.location.pathname - } - if(this.props.router!=undefined) - { - this.props.router.push(redirectURL) + // if(message=="PLEASE_LOGIN") + // { + // // Login required + // var redirectURL="/login" + // if(window!=undefined) + // { - } + // redirectURL +="?redirect="+window.location.pathname + // } + // if(this.props.router!=undefined) + // { + // this.props.router.push(redirectURL) - }else{ - toast.error(this.i18next.t(message)) + // } - } + + // }else{ + // toast.error(this.i18next.t(message)) + + // } } else { @@ -232,25 +240,33 @@ import { getAPIURL, logVar } from '@/helpers/general'; } else { var message= getMessageFromAPIResponse(response) + console.error("refreshCalendars", message, response) + if(message!=null) { - if(message=="PLEASE_LOGIN") + + if(message!="PLEASE_LOGIN") { - // Login required - var redirectURL="/login" - if(window!=undefined) - { + toast.error(this.i18next.t(message)) + } - redirectURL +="?redirect="+window.location.pathname - } - this.props.router.push(redirectURL) + // if(message=="PLEASE_LOGIN") + // { + // // Login required + // var redirectURL="/login" + // if(window!=undefined) + // { - }else{ - toast.error(this.i18next.t(message)) + // redirectURL +="?redirect="+window.location.pathname + // } + // this.props.router.push(redirectURL) - } + + // }else{ + + // } } else { diff --git a/src/components/tasks/TaskUI.js b/src/components/tasks/TaskUI.js index 1ea6706..52d339e 100644 --- a/src/components/tasks/TaskUI.js +++ b/src/components/tasks/TaskUI.js @@ -302,14 +302,15 @@ export default class TaskUI extends Component { } onTaskSubmittoServer(body) { this.setState({ showTaskEditModal: false, showTaskEditor: false }) + var message= getMessageFromAPIResponse(body) if (body != null) { if (body.success == true) { - toast.success(this.i18next.t(body.data.message)) + toast.success(this.i18next.t(message)) this.props.fetchEvents(body.data.refresh) } else { - toast.error(this.i18next.t(body.data.message)) + toast.error(message) } } @@ -321,7 +322,6 @@ export default class TaskUI extends Component { onSubtaskSubmittoServer(body) { this.setState({ showSubtaskEditor: false }) - if (body != null) { if (body.success == true) { toast.success(this.i18next.t("EVENT_SUBMIT_OK")) @@ -330,12 +330,12 @@ export default class TaskUI extends Component { } else { - toast.error(this.i18next.t(body.data.message)) + toast.error(this.i18next.t(message)) } } else { - toast.error(body) + toast.error(this.i18next.t("ERROR_GENERIC")) } } diff --git a/src/config/constants.js b/src/config/constants.js index b336e36..d3da4e6 100644 --- a/src/config/constants.js +++ b/src/config/constants.js @@ -1,4 +1,4 @@ -export const VERSION_NUMBER = "0.2.0" +export const VERSION_NUMBER = "0.3.0" /* * SYSTEM_DEFAULT_LABEL_PREFIX: Default prefix applied to all system generated labels like * "My Day" diff --git a/src/helpers/api/installSequelize.ts b/src/helpers/api/installSequelize.ts new file mode 100644 index 0000000..d648ffe --- /dev/null +++ b/src/helpers/api/installSequelize.ts @@ -0,0 +1,14 @@ +import { caldav_accounts } from "models/caldav_accounts" +import { calendar_events } from "models/calendar_events" +import { calendars } from "models/calendars" +import { custom_filters } from "models/custom_filters" +import { labels } from "models/labels" +import { otp_table } from "models/otp_table" +import {settings} from 'models/settings' +import { ssid_table } from "models/ssid_table" +import { users } from "models/users" + + +export async function isInstalledV2(){ + +} \ No newline at end of file diff --git a/src/helpers/api/user.js b/src/helpers/api/user.js index 366261c..bbbd555 100644 --- a/src/helpers/api/user.js +++ b/src/helpers/api/user.js @@ -1,10 +1,15 @@ -import { getConnectionVar } from '@/helpers/api/db'; +import { getConnectionVar, getSequelizeObj } from '@/helpers/api/db'; import crypto from "crypto" import { Base64 } from 'js-base64'; import { getRegistrationStatus, userRegistrationAllowed } from './settings'; import { varNotEmpty } from '../general'; import bcrypt from 'bcryptjs'; - +import { getUserIDFromNextAuthSession, nextAuthEnabled } from '../thirdparty/nextAuth'; +import { getServerSession } from 'next-auth'; +import { authOptions } from '@/pages/api/auth/[...nextauth]'; +import { getToken } from 'next-auth/jwt'; +import { getRandomString } from '../crypto'; +import { users } from 'models/users'; export async function getUserDetailsfromUsername(username) { var con = getConnectionVar() @@ -96,10 +101,10 @@ export async function forceInsertUserIntoDB(username,password,email,level) //var password = crypto.createHash('sha512').update(password).digest('hex') const salt = await bcrypt.genSalt(10) const passwordHash = await bcrypt.hash(password, salt) - + const id = getRandomString(16) var created=Math.floor(Date.now() / 1000) - con.query('INSERT INTO users (username, password, email, created, userhash,level) VALUES (?,?, ? ,?,?,?)', [username, passwordHash, email, created, userhash,level], function (error, results, fields) { + con.query('INSERT INTO users (username, password, email, created, userhash,level,id) VALUES (?,?, ? ,?,?,?,?)', [username, passwordHash, email, created, userhash,level, id], function (error, results, fields) { if (error) { console.log(error.message) } @@ -244,6 +249,40 @@ export async function getAllSSIDFromDB(userhash) } +export async function getUserIDFromLogin(req,res){ + if(!varNotEmpty(req) || !varNotEmpty(res)){ + return null + } + + if(nextAuthEnabled()){ + const session = await getServerSession(req, res, authOptions) + const id_fromNextAuth= getUserIDFromNextAuthSession(session) + return await getUserIDFromNextAuthID(id_fromNextAuth) + }else{ + var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + const userid = await getUseridFromUserhash(userHash[0]) + return userid + } + +} + +export async function getUserIDFromNextAuthID(id){ + + const Users= users.initModel(getSequelizeObj()) + const res = await Users.findOne({ + where:{ + id:id + }, + raw: true, + nest: true, + }) + + if(res && res.users_id){ + return res.users_id + } + return null +} + export async function getUserHashSSIDfromAuthorisation(authHeaders) { if(authHeaders!=null && authHeaders!="" && authHeaders!=undefined && authHeaders!="null") @@ -259,37 +298,46 @@ export async function getUserHashSSIDfromAuthorisation(authHeaders) } } -export async function middleWareForAuthorisation(authHeaders) +export async function middleWareForAuthorisation(req, res) { - try{ - if(authHeaders!=null && authHeaders!="" && authHeaders!=undefined &&authHeaders!="null") - { - - var userssidArray= await getUserHashSSIDfromAuthorisation(authHeaders) - if(userssidArray!=null && Array.isArray(userssidArray) && userssidArray.length==2) - { - - const isValid= await checkSSIDValidity(userssidArray[0], userssidArray[1]) - //console.log(isValid) - return isValid - - - } - else - { + if(!varNotEmpty(req)){ + return false + } + if(nextAuthEnabled()){ + const session = await getServerSession(req, res, authOptions) + if(session){ + return true + }else{ return false } - // - } - else - { - return false } - } - catch(e) - { - //console.log("middleWareForAuthorisation", e) - return false + else{ + try{ + const authHeaders = req.headers.authorization + + var userssidArray= await getUserHashSSIDfromAuthorisation(authHeaders) + if(userssidArray!=null && Array.isArray(userssidArray) && userssidArray.length==2) + { + + const isValid= await checkSSIDValidity(userssidArray[0], userssidArray[1]) + //console.log(isValid) + return isValid + + + } + else + { + return false + } + // + + } + catch(e) + { + //console.log("middleWareForAuthorisation", e) + return false + } + } } diff --git a/src/helpers/frontend/classes/APIRequests.js b/src/helpers/frontend/classes/APIRequests.js index 4eb7d03..6d92552 100644 --- a/src/helpers/frontend/classes/APIRequests.js +++ b/src/helpers/frontend/classes/APIRequests.js @@ -45,25 +45,32 @@ export class APIRequests{ toast.error(this.i18next.t("ERROR_GENERIC")) }else{ var message= getMessageFromAPIResponse(responseFromServer) + console.error("getAllTodosFromServer", message, responseFromServer) + if(message!=null) { - if(message=="PLEASE_LOGIN") + + if(message!=="PLEASE_LOGIN") { - // Login required - var redirectURL="/login" - if(window!=undefined) - { + toast.error(this.i18next.t(message)) + } + // if(message=="PLEASE_LOGIN") + // { + // // Login required + // var redirectURL="/login" + // if(window!=undefined) + // { - redirectURL +="?redirect="+window.location.pathname - } - this.props.router.push(redirectURL) + // redirectURL +="?redirect="+window.location.pathname + // } + // this.props.router.push(redirectURL) - }else{ - toast.error(this.i18next.t(message)) + // }else{ + // toast.error(this.i18next.t(message)) - } + // } } else { diff --git a/src/helpers/frontend/cookies.js b/src/helpers/frontend/cookies.js index b813c6f..4e134e1 100644 --- a/src/helpers/frontend/cookies.js +++ b/src/helpers/frontend/cookies.js @@ -3,6 +3,19 @@ import { getAuthenticationHeadersforUser } from './user' import { getAPIURL, logVar, varNotEmpty } from '../general' import { getMessageFromAPIResponse } from './response' +export function deleteAllCookies(){ + Cookies.remove("DEFAULT_CALENDAR_ID") + Cookies.remove("MMDL_USERNAME") + Cookies.remove("USER_SETTING_SYNCTIMEOUT") + Cookies.remove("USER_DATA_LABELS") + Cookies.remove("DEFAULT_VIEW_CALENDAR") + Cookies.remove("USERHASH") + Cookies.remove("USER_PREFERENCE_CALENDARS_TO_SHOW") + Cookies.remove("SSID") + + + +} export function setCookie(cname, cvalue, exdays=10000) { diff --git a/src/helpers/frontend/user.js b/src/helpers/frontend/user.js index 44f9052..471ca8c 100644 --- a/src/helpers/frontend/user.js +++ b/src/helpers/frontend/user.js @@ -1,6 +1,11 @@ import Cookies from "js-cookie"; import { getUserDB } from "./db"; import { Base64 } from "js-base64"; +import { nextAuthEnabled } from "../thirdparty/nextAuth"; +import { signOut } from "next-auth/react"; +import { getAPIURL, varNotEmpty } from "../general"; +import axios from "axios"; +import { deleteAllCookies } from "./cookies"; export async function getUserData() { @@ -22,6 +27,32 @@ export function logoutUser() Cookies.remove("SSID") Cookies.remove("USER_DATA_LABELS") Cookies.remove("USER_SETTING_SYNCTIMEOUT") + + deleteAllCookies() + //Logout nextAuth Sessions. + if(nextAuthEnabled()){ + signOut() + } +} + +/** + * Manages user logout with redirect. Calls the Logout function (which signs out the user either with NextAuth.js or with inbuilt mechanism, then redirects appropriately.) + */ +export function logoutUser_withRedirect(router, redirectURL){ + logoutUser() + if(varNotEmpty(router)){ + if(nextAuthEnabled()){ + router.push('/') + }else{ + var url = '/login' + if(varNotEmpty(redirectURL)){ + url+="/?redirect="+redirectURL + } + router.push(url) + + } + } + } export function getUserDataFromCookies() { return ({ @@ -40,4 +71,41 @@ export async function getAuthenticationHeadersforUser() { } export async function insertUserdata() { +} + + +export async function checkLogin_InBuilt(router, redirectURL){ + const url_api=getAPIURL()+"auth/inbuilt/check" + const authorisationData=await getAuthenticationHeadersforUser() + + const requestOptions = + { + method: 'GET', + mode: 'cors', + headers: new Headers({'authorization': authorisationData, 'Content-Type':'application/json'}), + } + + return new Promise( (resolve, reject) => { + fetch(url_api, requestOptions) + .then(response => response.json()) + .then((body) =>{ + if(varNotEmpty(body) && varNotEmpty(body.success)){ + if(body.success!=true){ + logoutUser_withRedirect(router, redirectURL) + } + + }else{ + logoutUser_withRedirect(router, redirectURL) + } + return resolve(true) + }).catch(e=> + { + + console.error("checkLogin_InBuilt", e) + return resolve(false) + + } + ) + + }) } \ No newline at end of file diff --git a/src/helpers/installation.ts b/src/helpers/installation.ts new file mode 100644 index 0000000..c15e8a9 --- /dev/null +++ b/src/helpers/installation.ts @@ -0,0 +1,3 @@ +export function isInstalledV2(){ + +} \ No newline at end of file diff --git a/src/helpers/models.ts b/src/helpers/models.ts new file mode 100644 index 0000000..aa55c00 --- /dev/null +++ b/src/helpers/models.ts @@ -0,0 +1,4 @@ +export function getAllDBModels(){ + + +} \ No newline at end of file diff --git a/src/helpers/thirdparty/keycloak.ts b/src/helpers/thirdparty/keycloak.ts new file mode 100644 index 0000000..f1e75e9 --- /dev/null +++ b/src/helpers/thirdparty/keycloak.ts @@ -0,0 +1,70 @@ +import Keycloak from 'keycloak-js'; +import { varNotEmpty } from '../general'; +import { getI18nObject } from '../frontend/general'; +const i18next = getI18nObject() + +/** + * Checks if the user is logged in. + * If no value of NEXT_PUBLIC_OPEN_ID_PROVIDER is provided as an environment variable + * we will assume that the user wants to use MMDL's inbuilt login functions. + * @returns Promise of a blooean. True if user is logged in. + */ +export async function isUserLoggedIn(): Promise{ + + if(!varNotEmpty(process.env.NEXT_PUBLIC_OPEN_ID_PROVIDER)){ + return true + } + + + try{ + switch (process.env.NEXT_PUBLIC_OPEN_ID_PROVIDER.trim().toUpperCase()){ + + case "KEYCLOAK": + return silentCheckSSO_KeyCloak(); + case "": + return true + default: + throw new Error(i18next.t("ERROR_INVALID_VALUE_OPENID_PROVIDER")) + + } + + }catch(e){ + console.error(e) + throw new Error(i18next.t("ERROR_INVALID_VALUE_OPENID_PROVIDER")) + } + + +} + +/** + * Checks if user is logged in with Keycloak. + * Uses check-sso in Keycloak initiation. + */ +export async function silentCheckSSO_KeyCloak(){ + const keycloak = new Keycloak({ + url: process.env.NEXT_PUBLIC_OPEN_ID_PROVIDER_URL, + realm: process.env.NEXT_PUBLIC_OPEN_ID_PROVIDER_REALM, + clientId: process.env.NEXT_PUBLIC_OPEN_ID_PROVIDER_CLIENT_ID + }); + + + try { + keycloak.init({onLoad: "login-required"}).then((authenticated) =>{ + + if(authenticated){ + return true + }else{ + return false + } + + }) + + } catch (error) { + console.log('Failed to initialize adapter:', error) + } + + return false + + + +} \ No newline at end of file diff --git a/src/helpers/thirdparty/nextAuth.ts b/src/helpers/thirdparty/nextAuth.ts new file mode 100644 index 0000000..277703e --- /dev/null +++ b/src/helpers/thirdparty/nextAuth.ts @@ -0,0 +1,26 @@ + +export function nextAuthEnabled(){ + if(process.env.NEXT_PUBLIC_USE_NEXT_AUTH==="true"){ + return true + }else{ + return false + } +} + +/** + * Takes in result of getServerSession from NextAuth.js + * and return the user id. + */ +export function getUserIDFromNextAuthSession(session: any) +{ + if(session){ + if(session.user) + { + if(session.user.id){ + return session.user.id + } + } + } + + return null +} \ No newline at end of file diff --git a/src/i18n/strings.json b/src/i18n/strings.json index 120e447..a206e58 100644 --- a/src/i18n/strings.json +++ b/src/i18n/strings.json @@ -82,6 +82,7 @@ "EVENT_NEEDS_BOTH_FROM_AND_TO": "Event needs both a 'From' and 'To' date.", "EVENT_SUBMIT_OK": "Event successfully added.", "EVENT_SUMMARY": "Event Summary", + "ERROR_INVALID_VALUE_OPENID_PROVIDER":"Invalid value of NEXT_PUBLIC_OPEN_ID_PROVIDER was provided as environment variable.", "EVERY": "Every", "FILTERS": "Filters", "FILTER_BY_DUE": "Filter by Due", diff --git a/src/pages/_app.js b/src/pages/_app.js index 882965b..77b3014 100644 --- a/src/pages/_app.js +++ b/src/pages/_app.js @@ -3,9 +3,8 @@ import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap-icons/font/bootstrap-icons.css' import { Toastify } from '@/components/Generic'; import 'react-toastify/dist/ReactToastify.css'; -import Script from 'next/script'; import '../styles/global.css' - +import { SessionProvider } from "next-auth/react" function load() { NProgress.start(); @@ -16,10 +15,13 @@ function stop() NProgress.done(); } -export default function App({ Component, pageProps }) { +export default function App({ Component, pageProps: {session, ...pageProps }}) { + return (<> - - - - ) + + + + + + ) } diff --git a/src/pages/accounts/caldav.js b/src/pages/accounts/caldav.js index f6a1ec5..98a9880 100644 --- a/src/pages/accounts/caldav.js +++ b/src/pages/accounts/caldav.js @@ -1,12 +1,32 @@ import Head from 'next/head' import Container from 'react-bootstrap/Container'; -import AppBarGeneric from "@/components/common/AppBarGeneric" +import AppBarGeneric from "@/components/common/AppBar" import CaldavAccounts from '@/components/common/calendars/caldavAccounts/CaldavAccounts' import { getI18n } from 'react-i18next'; import { getI18nObject } from '@/helpers/frontend/general'; +import { signIn, useSession } from 'next-auth/react'; +import { useEffect } from 'react'; +import { nextAuthEnabled } from '@/helpers/thirdparty/nextAuth'; +import { useRouter } from 'next/router'; +import { checkLogin_InBuilt } from '@/helpers/frontend/user'; export default function Caldav() { + const { data: session, status } = useSession() + const router = useRouter() + + useEffect(() =>{ + + if(nextAuthEnabled()){ + if (status=="unauthenticated" ) { + signIn() + } + }else{ + // Check login using inbuilt function. + checkLogin_InBuilt(router,"/accounts/caldav") + } + }, [status, router]) + var i18next = getI18nObject() return ( <> @@ -15,7 +35,7 @@ export default function Caldav() { - +
diff --git a/src/pages/accounts/settings.tsx b/src/pages/accounts/settings.tsx new file mode 100644 index 0000000..11d2918 --- /dev/null +++ b/src/pages/accounts/settings.tsx @@ -0,0 +1,35 @@ +import SettingsPage from "@/components/page/SettingsPage/SettingsPage"; +import { checkLogin_InBuilt, logoutUser_withRedirect } from "@/helpers/frontend/user"; +import { nextAuthEnabled } from "@/helpers/thirdparty/nextAuth"; +import { signIn, useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import { useEffect } from "react"; + + +export default function Settings(){ + const { data: session, status } = useSession() + const router = useRouter() + + useEffect(() =>{ + + if(nextAuthEnabled()){ + if (status=="unauthenticated" ) { + signIn() + } + }else{ + // Check login using inbuilt function. + + checkLogin_InBuilt(router, '/accounts/settings') + } + }, [status,router]) + + + + + + return( + <> + + + ) +} \ No newline at end of file diff --git a/src/pages/api/admin/deleteuser.js b/src/pages/api/admin/deleteuser.js index 33fd56d..3d2b258 100644 --- a/src/pages/api/admin/deleteuser.js +++ b/src/pages/api/admin/deleteuser.js @@ -1,17 +1,24 @@ import Settings from "@/helpers/api/classes/Settings" import { User } from "@/helpers/api/classes/User" import { getICS } from "@/helpers/api/ical" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { varNotEmpty } from "@/helpers/general" import moment from "moment" export default async function handler(req, res) { if (req.method === 'DELETE') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if( await middleWareForAuthorisation(req, res)) { if(varNotEmpty(req.query.userid)&& req.query.userid!="") { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + + var userObj = new User(userid) var isAdmin= await userObj.isAdmin() diff --git a/src/pages/api/admin/getusers.js b/src/pages/api/admin/getusers.js index 8a5acb1..05d4405 100644 --- a/src/pages/api/admin/getusers.js +++ b/src/pages/api/admin/getusers.js @@ -1,16 +1,22 @@ import Settings from "@/helpers/api/classes/Settings" import { User } from "@/helpers/api/classes/User" import { getICS } from "@/helpers/api/ical" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { varNotEmpty } from "@/helpers/general" import moment from "moment" export default async function getusers_handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var userObj = new User(userid) var isAdmin= await userObj.isAdmin() diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js new file mode 100644 index 0000000..2f3a3e7 --- /dev/null +++ b/src/pages/api/auth/[...nextauth].js @@ -0,0 +1,22 @@ +import authProviders from "config/nextAuthProviders" +import NextAuth from "next-auth" +import SequelizeAdapter from "@auth/sequelize-adapter"; +import { Sequelize } from "sequelize"; +import { getSequelizeObj } from "@/helpers/api/db"; + +const sequelize = getSequelizeObj() + +export const authOptions = { + // Configure one or more authentication providers + providers:authProviders, + adapter: SequelizeAdapter(sequelize,{ + synchronize: false + }), + callbacks: { + session: async (session, user) => { + return Promise.resolve(session) + } + } +} + +export default NextAuth(authOptions) \ No newline at end of file diff --git a/src/pages/api/auth/inbuilt/check.js b/src/pages/api/auth/inbuilt/check.js new file mode 100644 index 0000000..e4c5011 --- /dev/null +++ b/src/pages/api/auth/inbuilt/check.js @@ -0,0 +1,15 @@ +import { middleWareForAuthorisation } from "@/helpers/api/user"; + +export default async function checkLoginHandler(req, res) { + if (req.method === 'GET') { + if(await middleWareForAuthorisation(req, res)) + { + res.status(200).json({ success: true, data: { message: 'LOGIN_OK'} }) + + }else{ + res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + + } +} \ No newline at end of file diff --git a/src/pages/api/caldav/calendars/add/event.js b/src/pages/api/caldav/calendars/add/event.js index b6d9654..30492a4 100644 --- a/src/pages/api/caldav/calendars/add/event.js +++ b/src/pages/api/caldav/calendars/add/event.js @@ -2,20 +2,25 @@ import { createEventinCalDAVAccount } from '@/helpers/api/cal/caldav'; import { checkifUserHasAccesstoRequestedCalendar, getCaldavAccountfromUserID, getCaldavAccountIDFromCalendarID, getCalendarfromCalendarID } from '@/helpers/api/cal/calendars'; import { getAllLablesFromDB } from '@/helpers/api/cal/labels'; import { getObjectFromDB, insertObjectIntoDB, updateObjectinDB } from '@/helpers/api/cal/object'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; import { getRandomString } from '@/helpers/crypto'; import { logVar } from '@/helpers/general'; export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { //console.log(req.body) if(req.body.etag!=null && req.body.etag.trim()!="" && req.body.data!=null && req.body.data.trim()!="" && req.body.updated!=null && req.body.updated.toString().trim()!="" && req.body.type!=null && req.body.type.trim()!="" && req.body.calendar_id!=null && req.body.calendar_id.toString().trim()!="") { logVar(req.body.data, '/api/caldav/calendars/add/event') - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) - var userid = await getUseridFromUserhash(userHash[0]) + // var userid = await getUseridFromUserhash(userHash[0]) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } //First we check if user has access to calendar. var currentCaldavAccountID=await getCaldavAccountIDFromCalendarID(req.body.calendar_id) diff --git a/src/pages/api/caldav/calendars/events/all.js b/src/pages/api/caldav/calendars/events/all.js index ff637bf..c325706 100644 --- a/src/pages/api/caldav/calendars/events/all.js +++ b/src/pages/api/caldav/calendars/events/all.js @@ -3,19 +3,26 @@ import { getCaldavAccountsfromUserid, getCalendarsfromCaldavAccountsID } from '@ import { updateLabels } from '@/helpers/api/cal/labels'; import { User } from '@/helpers/api/classes/User'; import { process_calendarQueryResults } from '@/helpers/api/tsdav'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; import { logVar } from '@/helpers/general'; const LOGTAG= "Source: /api/caldav/calendars/events/all" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { logVar(req.query, LOGTAG) if(req.query.caldav_accounts_id!=null) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) - var userid = await getUseridFromUserhash(userHash[0]) + // var userid = await getUseridFromUserhash(userHash[0]) + + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var userObj = new User(userid) //console.log("hasAccesstoCaldavAccountID", ) if(await userObj.hasAccesstoCaldavAccountID(req.query.caldav_accounts_id)) diff --git a/src/pages/api/caldav/calendars/events/db/all.js b/src/pages/api/caldav/calendars/events/db/all.js index ce3d594..3b103ee 100644 --- a/src/pages/api/caldav/calendars/events/db/all.js +++ b/src/pages/api/caldav/calendars/events/db/all.js @@ -1,16 +1,23 @@ import { checkifUserHasAccesstoRequestedCalendar, getCaldavAccountsfromUserid, getCalendarsfromCaldavAccountsID } from "@/helpers/api/cal/calendars" import { getCalendarObjectsFromCalendar, getCalendarObjectsFromCalendarbyType } from "@/helpers/api/cal/object" -import { getUserHashSSIDfromAuthorisation, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserHashSSIDfromAuthorisation, getUserIDFromLogin, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + + // var userid = await getUseridFromUserhash(userHash[0]) + + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } - var userid = await getUseridFromUserhash(userHash[0]) var allCalendarEvents =[] var caldav_accounts = await getCaldavAccountsfromUserid(userid) if(caldav_accounts!=null && Array.isArray(caldav_accounts) && caldav_accounts.length>0) diff --git a/src/pages/api/caldav/calendars/events/db/index.js b/src/pages/api/caldav/calendars/events/db/index.js index 74cf5b8..aef97ea 100644 --- a/src/pages/api/caldav/calendars/events/db/index.js +++ b/src/pages/api/caldav/calendars/events/db/index.js @@ -1,17 +1,24 @@ import { checkifUserHasAccesstoRequestedCalendar, getCaldavAccountsfromUserid } from "@/helpers/api/cal/calendars" import { getCalendarObjectsFromCalendar, getCalendarObjectsFromCalendarbyType } from "@/helpers/api/cal/object" -import { getUserHashSSIDfromAuthorisation, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserHashSSIDfromAuthorisation, getUserIDFromLogin, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.query.caldav_accounts_id!=null && req.query.calendars_id!=null) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + + // var userid = await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + - var userid = await getUseridFromUserhash(userHash[0]) var allCalendarEvents =null var calendar=await checkifUserHasAccesstoRequestedCalendar(userid, req.query.caldav_accounts_id, req.query.calendars_id) diff --git a/src/pages/api/caldav/calendars/events/fetchevents.js b/src/pages/api/caldav/calendars/events/fetchevents.js index db4e767..97a49a2 100644 --- a/src/pages/api/caldav/calendars/events/fetchevents.js +++ b/src/pages/api/caldav/calendars/events/fetchevents.js @@ -1,18 +1,24 @@ import { checkifUserHasAccesstoRequestedCalendar } from '@/helpers/api/cal/calendars'; -import { checkSSIDValidity, getUserHashSSIDfromAuthorisation, getUseridFromUserhash, middleWareForAuthorisation } from '@/helpers/api/user'; +import { checkSSIDValidity, getUserHashSSIDfromAuthorisation, getUserIDFromLogin, getUseridFromUserhash, middleWareForAuthorisation } from '@/helpers/api/user'; import { getCaldavClient, saveCalendarEventsintoDB } from '@/helpers/api/cal/caldav'; import { DAVNamespace } from 'tsdav'; export default async function handler(req, res) { if (req.method === 'GET') { if(req.query.caldav_account_id!=null && req.query.calendar_id!=null) { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if( await middleWareForAuthorisation(req,res)) { var calendarObjects = null - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + + // var userid = await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } - var userid = await getUseridFromUserhash(userHash[0]) var calendar=await checkifUserHasAccesstoRequestedCalendar(userid, req.query.caldav_account_id, req.query.calendar_id) if(calendar!=null) { diff --git a/src/pages/api/caldav/calendars/events/refresh.js b/src/pages/api/caldav/calendars/events/refresh.js index a1743ad..e8fe787 100644 --- a/src/pages/api/caldav/calendars/events/refresh.js +++ b/src/pages/api/caldav/calendars/events/refresh.js @@ -1,16 +1,23 @@ import { getCaldavClient, saveCalendarEventsintoDB } from '@/helpers/api/cal/caldav'; import { getCaldavAccountsfromUserid, getCalendarsfromCaldavAccountsID } from '@/helpers/api/cal/calendars'; import { updateLabels } from '@/helpers/api/cal/labels'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req.headers.authorization)) { if(req.query.caldav_accounts_id!=null) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + + // var userid = await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + - var userid = await getUseridFromUserhash(userHash[0]) var calendarObjectsArray = [] var caldav_accounts= await getCaldavAccountsfromUserid(userid) diff --git a/src/pages/api/caldav/calendars/index.js b/src/pages/api/caldav/calendars/index.js index 2c3b4b5..c6fe1c5 100644 --- a/src/pages/api/caldav/calendars/index.js +++ b/src/pages/api/caldav/calendars/index.js @@ -1,14 +1,18 @@ import { getCalendarsfromCaldavAccountsID, getCaldavAccountsfromUserid } from "@/helpers/api/cal/calendars" import { getCaldavAccountfromUserID } from '@/helpers/api/cal/calendars'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req, res)) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) - var userid = await getUseridFromUserhash(userHash[0]) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var final_caldav_account_array=[] var caldav_accounts= await getCaldavAccountsfromUserid(userid) if(caldav_accounts!=null&&Array.isArray(caldav_accounts)&&caldav_accounts.length>0) diff --git a/src/pages/api/caldav/calendars/labels/index.js b/src/pages/api/caldav/calendars/labels/index.js index a20f96a..838feef 100644 --- a/src/pages/api/caldav/calendars/labels/index.js +++ b/src/pages/api/caldav/calendars/labels/index.js @@ -1,13 +1,18 @@ import { getCaldavAccountfromUserID } from '@/helpers/api/cal/calendars'; import { getAllLablesFromDB } from '@/helpers/api/cal/labels'; import { User } from '@/helpers/api/classes/User'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - var userid=await User.idFromAuthorisation(req.headers.authorization) - + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + const labels = await getAllLablesFromDB(userid) res.status(200).json({ success: true, data: { message: labels} }) diff --git a/src/pages/api/caldav/calendars/modify/object.js b/src/pages/api/caldav/calendars/modify/object.js index fcdcdcb..54238f0 100644 --- a/src/pages/api/caldav/calendars/modify/object.js +++ b/src/pages/api/caldav/calendars/modify/object.js @@ -1,5 +1,5 @@ import { getObjectFromDB, insertObjectIntoDB, updateObjectinDB } from '@/helpers/api/cal/object'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; import { checkifUserHasAccesstoRequestedCalendar, getCaldavAccountIDFromCalendarID } from '@/helpers/api/cal/calendars'; import { getRandomString } from '@/helpers/crypto'; import { updateEventinCalDAVAccount } from '@/helpers/api/cal/caldav'; @@ -9,14 +9,20 @@ import { logVar } from '@/helpers/general'; export default async function handler(req, res) { logVar(req.body, "modify object API CALL") if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.body.url!=null && req.body.url.trim()!="" && req.body.etag!=null && req.body.etag.trim()!="" && req.body.data!=null && req.body.data.trim()!="" && req.body.updated!=null && req.body.updated.toString().trim()!="" && req.body.type!=null && req.body.type.trim()!="" && req.body.deleted!=null && req.body.calendar_id!=null && req.body.calendar_id.trim()!="") { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + + // var userid = await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } - var userid = await getUseridFromUserhash(userHash[0]) var caldav_accounts_id= await getCaldavAccountIDFromCalendarID(req.body.calendar_id) //First we check if user has access to calendar. var calendarFromDB= await checkifUserHasAccesstoRequestedCalendar(userid, caldav_accounts_id,req.body.calendar_id) diff --git a/src/pages/api/caldav/calendars/name.js b/src/pages/api/caldav/calendars/name.js index 27de336..b081261 100644 --- a/src/pages/api/caldav/calendars/name.js +++ b/src/pages/api/caldav/calendars/name.js @@ -1,16 +1,22 @@ import { getCaldavAccountDetailsfromId } from "@/helpers/api/cal/caldav" import { checkifUserHasAccesstoRequestedCalendar, getCaldavAccountsfromUserid } from "@/helpers/api/cal/calendars" -import { getUserHashSSIDfromAuthorisation, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserHashSSIDfromAuthorisation, getUserIDFromLogin, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.query.caldav_accounts_id!=null && req.query.calendars_id!=null && req.query.calendars_id!="" && req.query.caldav_accounts_id!="") { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) - var userid = await getUseridFromUserhash(userHash[0]) + // var userid = await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var allCalendarEvents =null var calendar=await checkifUserHasAccesstoRequestedCalendar(userid, req.query.caldav_accounts_id, req.query.calendars_id) var caldavDetails= await getCaldavAccountDetailsfromId(req.query.caldav_accounts_id) diff --git a/src/pages/api/caldav/calendars/sync/all.js b/src/pages/api/caldav/calendars/sync/all.js index 81888d0..c55790b 100644 --- a/src/pages/api/caldav/calendars/sync/all.js +++ b/src/pages/api/caldav/calendars/sync/all.js @@ -1,18 +1,25 @@ import { getCaldavAccountDetailsfromId } from "@/helpers/api/cal/caldav" import { checkifCalendarExistforUser, deleteCalendarFromDB, getCaldavAccountsAllData, getCaldavAccountsfromUserid, getCalendarsfromCaldavAccountsID, insertCalendarintoDB, updateCalendarinDB } from "@/helpers/api/cal/calendars" import { getCalendarObjectsFromCalendarbyType } from "@/helpers/api/cal/object" -import { getUserHashSSIDfromAuthorisation, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserHashSSIDfromAuthorisation, getUserIDFromLogin, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" import { isValidResultArray } from "@/helpers/general" import { AES } from "crypto-js" import { createDAVClient } from "tsdav" import CryptoJS from "crypto-js" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + + // var userid = await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + - var userid = await getUseridFromUserhash(userHash[0]) var allCaldavAccountBasicData = await getCaldavAccountsAllData(userid) if(isValidResultArray(allCaldavAccountBasicData)) { diff --git a/src/pages/api/caldav/calendars/sync/one.js b/src/pages/api/caldav/calendars/sync/one.js index 1064779..c0a71b7 100644 --- a/src/pages/api/caldav/calendars/sync/one.js +++ b/src/pages/api/caldav/calendars/sync/one.js @@ -1,21 +1,28 @@ import { getCaldavAccountDetailsfromId } from "@/helpers/api/cal/caldav" import { getCaldavAccountsAllData, getCaldavAccountsfromUserid, getCalendarsfromCaldavAccountsID } from "@/helpers/api/cal/calendars" import { getCalendarObjectsFromCalendarbyType } from "@/helpers/api/cal/object" -import { getUserHashSSIDfromAuthorisation, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserHashSSIDfromAuthorisation, getUserIDFromLogin, getUseridFromUserhash, middleWareForAuthorisation } from "@/helpers/api/user" import { isValidResultArray } from "@/helpers/general" import { AES } from "crypto-js" import { createDAVClient } from "tsdav" import CryptoJS from "crypto-js" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.query.calendar_id!=null) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + + // var userid = await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + - var userid = await getUseridFromUserhash(userHash[0]) var allCaldavAccountBasicData = await getCaldavAccountsAllData(userid) if(isValidResultArray(allCaldavAccountBasicData)) { diff --git a/src/pages/api/caldav/delete.js b/src/pages/api/caldav/delete.js index 7d1b143..9af7c81 100644 --- a/src/pages/api/caldav/delete.js +++ b/src/pages/api/caldav/delete.js @@ -1,15 +1,21 @@ -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { User } from '@/helpers/api/classes/User'; import { CaldavAccount } from "@/helpers/api/classes/CaldavAccount"; import { Calendars } from "@/helpers/api/classes/Calendars"; export default async function handler(req, res) { if (req.method === 'DELETE') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if( await middleWareForAuthorisation(req,res)) { if(req.query.caldav_account_id!=null &&req.query.caldav_account_id!=""&&req.query.caldav_account_id!=undefined) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var user = new User(userid) var userHasAcess= await user.hasAccesstoCaldavAccountID(req.query.caldav_account_id) if (userHasAcess) diff --git a/src/pages/api/caldav/event/delete.js b/src/pages/api/caldav/event/delete.js index b7f7c02..6d09174 100644 --- a/src/pages/api/caldav/event/delete.js +++ b/src/pages/api/caldav/event/delete.js @@ -2,19 +2,25 @@ import { createEventinCalDAVAccount, getCaldavAccountDetailsfromId } from '@/hel import { checkifUserHasAccesstoRequestedCalendar, getCaldavAccountfromUserID, getCaldavAccountIDFromCalendarID, getCalendarfromCalendarID } from '@/helpers/api/cal/calendars'; import { getAllLablesFromDB } from '@/helpers/api/cal/labels'; import { deleteCalendarObjectsFromDB, getObjectFromDB, insertObjectIntoDB, updateObjectinDB } from '@/helpers/api/cal/object'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; import { getRandomString } from '@/helpers/crypto'; import { AES } from 'crypto-js'; import { createDAVClient, deleteCalendarObject } from 'tsdav'; import CryptoJS from 'crypto-js'; export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if( await middleWareForAuthorisation(req,res)) { if(req.body.etag!=null && req.body.etag.trim()!="" && req.body.calendar_id!=null && req.body.calendar_id.toString().trim()!=""&&req.body.url!=null && req.body.url.trim()!="") { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) - var userid = await getUseridFromUserhash(userHash[0]) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userid = await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var currentCaldavAccountID=await getCaldavAccountIDFromCalendarID(req.body.calendar_id) var currentCalendar= await checkifUserHasAccesstoRequestedCalendar(userid, currentCaldavAccountID, req.body.calendar_id) if(currentCalendar!=null) diff --git a/src/pages/api/caldav/index.js b/src/pages/api/caldav/index.js index 6a2759c..eeb9fee 100644 --- a/src/pages/api/caldav/index.js +++ b/src/pages/api/caldav/index.js @@ -1,11 +1,17 @@ import { getCaldavAccountfromUserID } from '@/helpers/api/cal/calendars'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if( await middleWareForAuthorisation(req,res)) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) - var userid=await getUseridFromUserhash(userHash[0]) + // var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) + // var userid=await getUseridFromUserhash(userHash[0]) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + const caldavAccounts =await getCaldavAccountfromUserID(userid) res.status(200).json({ success: true, data: { message: caldavAccounts} }) diff --git a/src/pages/api/caldav/register.js b/src/pages/api/caldav/register.js index 323beba..69d423f 100644 --- a/src/pages/api/caldav/register.js +++ b/src/pages/api/caldav/register.js @@ -2,21 +2,26 @@ import validator from 'validator'; import { createDAVClient, DAVClient, getBasicAuthHeaders } from 'tsdav'; import { caldavAccountExistinDB, insertCalendarsintoDB, isValidCaldavAccount, getCaldavAccountfromDetails, insertCalendarintoDB, checkifCalendarExistforUser } from '@/helpers/api/cal/calendars' import { getConnectionVar } from '@/helpers/api/db'; -import { middleWareForAuthorisation, getUseridFromUserhash, getUserHashSSIDfromAuthorisation } from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash, getUserHashSSIDfromAuthorisation, getUserIDFromLogin } from '@/helpers/api/user'; import { createCalDAVAccount } from '@/helpers/api/cal/caldav'; import { AES } from 'crypto-js'; import { logError, logVar } from '@/helpers/general'; export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + if(req.query.url!=null && req.query.username!=null && req.query.accountname!=null &&req.query.password!=null) { if ((req.query.url!=null&&validator.isURL(req.query.url)) || req.query.url.startsWith("http://localhost") || req.query.url.startsWith("https://localhost") ){ if(req.query.username!=null&&req.query.password!=null) { - var userHash= await getUserHashSSIDfromAuthorisation(req.headers.authorization) var url = req.query.url var username = validator.escape(req.query.username) @@ -33,7 +38,7 @@ export default async function handler(req, res) { defaultAccountType: 'caldav', }).catch((reason)=>{ logError(reason, "api/caldav/register client:") - res.status(401).json({ success: false, data: {message: reason.message}}) + return res.status(401).json({ success: false, data: {message: reason.message}}) }) @@ -43,7 +48,9 @@ export default async function handler(req, res) { //Caldav authentication was succesful. We'll save the details in the db now. if(calendars!=null) { - var answer= await saveDatatoDatabase(accountname, username, password, url, calendars, userHash[0]) + + + var answer= await saveDatatoDatabase(accountname, username, password, url, calendars, userid) res.status(200).json({ success: true, data: answer}) }else @@ -96,10 +103,9 @@ export default async function handler(req, res) { } } -async function saveDatatoDatabase(accountname, username, password, url, calendars,userhash) +async function saveDatatoDatabase(accountname, username, password, url, calendars,userid) { - var userid = await getUseridFromUserhash(userhash) var calDavAccountIsInDb=await caldavAccountExistinDB(username, url) if(calDavAccountIsInDb==false || (calDavAccountIsInDb!=null&&calDavAccountIsInDb.length==0)) { diff --git a/src/pages/api/calendars/create.js b/src/pages/api/calendars/create.js index 9e8e70e..46c16fd 100644 --- a/src/pages/api/calendars/create.js +++ b/src/pages/api/calendars/create.js @@ -1,7 +1,7 @@ import { CaldavAccount } from "@/helpers/api/classes/CaldavAccount" import { Calendars } from "@/helpers/api/classes/Calendars" import { User } from "@/helpers/api/classes/User" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { addTrailingSlashtoURL, getRandomColourCode, isValidResultArray, replaceSpacewithHyphen } from "@/helpers/general" import { AES } from "crypto-js" import { createDAVClient } from "tsdav" @@ -9,11 +9,18 @@ import CryptoJS from "crypto-js" export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.body.caldav_accounts_id!=null && req.body.caldav_accounts_id!=""&&req.body.calendarName!=null&&req.body.calendarName!="") { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var user = new User(userid) var caldav_accounts= await user.getCaldavAccountsAllData() var caldavAccountFound=-1 diff --git a/src/pages/api/calendars/refresh.js b/src/pages/api/calendars/refresh.js index b7257f7..9c0835c 100644 --- a/src/pages/api/calendars/refresh.js +++ b/src/pages/api/calendars/refresh.js @@ -1,7 +1,7 @@ import { CaldavAccount } from "@/helpers/api/classes/CaldavAccount" import { Calendars } from "@/helpers/api/classes/Calendars" import { User } from "@/helpers/api/classes/User" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { isValidResultArray, logVar } from "@/helpers/general" import { AES } from "crypto-js" import { createDAVClient } from "tsdav" @@ -9,9 +9,16 @@ import CryptoJS from "crypto-js" const LOGTAG = "api/calendars/refresh" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var user = new User(userid) var caldav_accounts= await user.getCaldavAccountsAllData() var finalResponse= [] diff --git a/src/pages/api/events/fetchOne.js b/src/pages/api/events/fetchOne.js index 5082ebc..224675b 100644 --- a/src/pages/api/events/fetchOne.js +++ b/src/pages/api/events/fetchOne.js @@ -1,14 +1,20 @@ import { Calendars } from "@/helpers/api/classes/Calendars" import { User } from "@/helpers/api/classes/User" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.query.calendar_id!=null && req.query.calendar_id!=""&&req.query.url!=null&&req.query.url!=""&&req.query.caldav_accounts_id!=null && req.query.caldav_accounts_id!="") { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var user = new User(userid) var calendar=await Calendars.getFromID(req.query.calendar_id) if(calendar!=null && calendar.calendars_id!=null) diff --git a/src/pages/api/events/search.js b/src/pages/api/events/search.js index 72670e9..009f166 100644 --- a/src/pages/api/events/search.js +++ b/src/pages/api/events/search.js @@ -1,18 +1,25 @@ import { CaldavAccount } from "@/helpers/api/classes/CaldavAccount" import { Calendars } from "@/helpers/api/classes/Calendars" import { User } from "@/helpers/api/classes/User" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { returnGetParsedVTODO } from "@/helpers/frontend/calendar" import { applyTaskFilter, majorTaskFilter } from "@/helpers/frontend/events" import { haystackHasNeedle } from "@/helpers/general" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.query.calendar_id!=null && req.query.calendar_id!=""&& req.query.calendar_id!=undefined && req.query.search_term!="" && req.query.search_term!=undefined && req.query.search_term!=null) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var user = new User(userid) var calendarObject= {calendars_id: req.query.calendar_id} var caldav_id = await CaldavAccount.getIDFromCalendar(calendarObject) diff --git a/src/pages/api/filters/add.js b/src/pages/api/filters/add.js index b24f40c..d47eca0 100644 --- a/src/pages/api/filters/add.js +++ b/src/pages/api/filters/add.js @@ -1,14 +1,19 @@ import { User } from '@/helpers/api/classes/User'; import { insertNewFiltertoDB } from '@/helpers/api/filter'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; import validator from 'validator'; export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if( await middleWareForAuthorisation(req,res)) { if(req.body.name!=null && req.body.name!=""&&req.body.filtervalue!=null&&req.body.filtervalue!="") { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } var jsonToInsert = JSON.stringify(req.body.filtervalue) var dbInsertResponse = insertNewFiltertoDB(req.body.name, jsonToInsert, userid) res.status(200).json({ success: true, data: { message: "FILTER_INSERT_OK"} }) diff --git a/src/pages/api/filters/delete.js b/src/pages/api/filters/delete.js index 1565e5b..595c9b6 100644 --- a/src/pages/api/filters/delete.js +++ b/src/pages/api/filters/delete.js @@ -1,14 +1,19 @@ import { Filters } from '@/helpers/api/classes/Filters'; import { User } from '@/helpers/api/classes/User'; import { getFiltersFromDB } from '@/helpers/api/filter'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'DELETE') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.query.filterid!=null &&req.query.filterid!=""&&req.query.filterid!=undefined) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } var filterObject= new Filters(req.query.filterid) diff --git a/src/pages/api/filters/get.js b/src/pages/api/filters/get.js index eefcc43..b3bc433 100644 --- a/src/pages/api/filters/get.js +++ b/src/pages/api/filters/get.js @@ -1,12 +1,17 @@ -import { User } from '@/helpers/api/classes/User'; import { getFiltersFromDB } from '@/helpers/api/filter'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req, res)) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var allLabels= await getFiltersFromDB(userid) res.status(200).json({ success: true, data: { message: allLabels} }) diff --git a/src/pages/api/filters/modify.js b/src/pages/api/filters/modify.js index 813cb42..3a96512 100644 --- a/src/pages/api/filters/modify.js +++ b/src/pages/api/filters/modify.js @@ -1,15 +1,20 @@ import { User } from '@/helpers/api/classes/User'; import { insertNewFiltertoDB, updateFilterinDB } from '@/helpers/api/filter'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; import validator from 'validator'; export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - console.log(req.body) if(req.body.custom_filters_id!=undefined && req.body.custom_filters_id!=null && req.body.custom_filters_id!="" && req.body.name!=undefined && req.body.name!=null && req.body.name!="" && req.body.filtervalue!=null&&req.body.filtervalue!="") { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var jsonToInsert = JSON.stringify(req.body.filtervalue) var dbInsertResponse = await updateFilterinDB(req.body.custom_filters_id, req.body.name, jsonToInsert, userid) var response = "FILTER_UPDATE_OK" diff --git a/src/pages/api/labels/modifycolor.js b/src/pages/api/labels/modifycolor.js index 95a8efe..2a0ab00 100644 --- a/src/pages/api/labels/modifycolor.js +++ b/src/pages/api/labels/modifycolor.js @@ -1,11 +1,16 @@ import { modifyLabelColour, updateLabels } from '@/helpers/api/cal/labels'; import { User } from '@/helpers/api/classes/User'; -import { middleWareForAuthorisation, } from '@/helpers/api/user'; +import { getUserIDFromLogin, middleWareForAuthorisation, } from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if( await middleWareForAuthorisation(req,res)) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + if(req.body.labelname!=null &&req.body.labelname!=""&&req.body.labelname!=undefined && req.body.colour!=null &&req.body.colour!=""&&req.body.colour!=undefined) { diff --git a/src/pages/api/labels/updatecache.js b/src/pages/api/labels/updatecache.js index 136ddbb..f23ef29 100644 --- a/src/pages/api/labels/updatecache.js +++ b/src/pages/api/labels/updatecache.js @@ -1,11 +1,16 @@ import { updateLabels } from '@/helpers/api/cal/labels'; -import { User } from '@/helpers/api/classes/User'; -import { middleWareForAuthorisation, } from '@/helpers/api/user'; +import { getUserIDFromLogin, middleWareForAuthorisation, } from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + const labels = await updateLabels(userid) res.status(200).json({ success: true, data: { message: "LABELS_UPDATED"} }) diff --git a/src/pages/api/misc/generateics.js b/src/pages/api/misc/generateics.js index 83e1ff6..d0f6242 100644 --- a/src/pages/api/misc/generateics.js +++ b/src/pages/api/misc/generateics.js @@ -6,7 +6,7 @@ import moment from "moment" export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(varNotEmpty(req.body.obj)) { diff --git a/src/pages/api/misc/parseics.js b/src/pages/api/misc/parseics.js index 033a093..5d8ff15 100644 --- a/src/pages/api/misc/parseics.js +++ b/src/pages/api/misc/parseics.js @@ -2,7 +2,7 @@ import { middleWareForAuthorisation } from "@/helpers/api/user" export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { var icalToolkit = require('ical-toolkit'); var json = icalToolkit.parseToJSON(req.body.ics); diff --git a/src/pages/api/misc/parseics_ical.js b/src/pages/api/misc/parseics_ical.js index 5522085..f77499d 100644 --- a/src/pages/api/misc/parseics_ical.js +++ b/src/pages/api/misc/parseics_ical.js @@ -3,7 +3,7 @@ import ICAL from '@/../ical.js/build/ical' import { isValidResultArray, logError, varNotEmpty } from "@/helpers/general"; export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { var type="vevent" var dataICS= req.body.ics diff --git a/src/pages/api/settings/get.js b/src/pages/api/settings/get.js index ca9f3a6..19e36f4 100644 --- a/src/pages/api/settings/get.js +++ b/src/pages/api/settings/get.js @@ -1,15 +1,21 @@ import Settings from "@/helpers/api/classes/Settings" import { User } from "@/helpers/api/classes/User" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { varNotEmpty } from "@/helpers/general" import moment from "moment" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var userObj = new User(userid) var isAdmin= await userObj.isAdmin() var settingKeys = await Settings.getAllforUserid(userid) diff --git a/src/pages/api/settings/getone.js b/src/pages/api/settings/getone.js index 7cb2678..d4a83c9 100644 --- a/src/pages/api/settings/getone.js +++ b/src/pages/api/settings/getone.js @@ -1,17 +1,23 @@ import Settings from "@/helpers/api/classes/Settings" import { User } from "@/helpers/api/classes/User" import { getICS } from "@/helpers/api/ical" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { varNotEmpty } from "@/helpers/general" import moment from "moment" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(varNotEmpty(req.query.name)&& req.query.name!="") { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var userObj = new User(userid) var isGlobal =false if(req.query.name.startsWith("GLOBAL_")) diff --git a/src/pages/api/settings/modify.js b/src/pages/api/settings/modify.js index 2eea940..111e3a4 100644 --- a/src/pages/api/settings/modify.js +++ b/src/pages/api/settings/modify.js @@ -1,17 +1,22 @@ import Settings from "@/helpers/api/classes/Settings" import { User } from "@/helpers/api/classes/User" import { getICS } from "@/helpers/api/ical" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { varNotEmpty } from "@/helpers/general" import moment from "moment" export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { //console.log(req.body) if(varNotEmpty(req.body.name) && req.body.name.toString().trim()!="" && varNotEmpty(req.body.value) && req.body.value.toString().trim()!=""){ - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } var userObj = new User(userid) var isGlobal =false diff --git a/src/pages/api/tasks/rrule/getrepeatobj.js b/src/pages/api/tasks/rrule/getrepeatobj.js index 912128d..ee55fbf 100644 --- a/src/pages/api/tasks/rrule/getrepeatobj.js +++ b/src/pages/api/tasks/rrule/getrepeatobj.js @@ -3,15 +3,21 @@ import { Events } from '@/helpers/api/classes/Events'; import { Filters } from '@/helpers/api/classes/Filters'; import { User } from '@/helpers/api/classes/User'; import { getFiltersFromDB } from '@/helpers/api/filter'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.query.calendar_event_id!=null &&req.query.calendar_event_id!=""&&req.query.calendar_event_id!=undefined) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var metaObject = new EventMeta({calendar_events_id: req.query.calendar_event_id, userid: userid, property: "REPEAT_META"}) const userHasAccess = await metaObject.userHasAccess(userid) diff --git a/src/pages/api/tasks/rrule/postrepeatobj.js b/src/pages/api/tasks/rrule/postrepeatobj.js index 138fe8b..7a6d336 100644 --- a/src/pages/api/tasks/rrule/postrepeatobj.js +++ b/src/pages/api/tasks/rrule/postrepeatobj.js @@ -1,16 +1,22 @@ import EventMeta from '@/helpers/api/classes/EventMeta'; import { Events } from '@/helpers/api/classes/Events'; import { User } from '@/helpers/api/classes/User'; -import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation} from '@/helpers/api/user'; +import { middleWareForAuthorisation, getUseridFromUserhash , getUserHashSSIDfromAuthorisation, getUserIDFromLogin} from '@/helpers/api/user'; import { logVar, varNotEmpty } from '@/helpers/general'; export default async function handler(req, res) { if (req.method === 'POST') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { if(req.body.calendar_event_id!=null &&req.body.calendar_event_id!=""&&req.body.calendar_event_id!=undefined && varNotEmpty(req.body.value) && req.body.value!="") { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + const userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var metaObject = new EventMeta({calendar_events_id: req.body.calendar_event_id, userid: userid, property: "REPEAT_META", value:req.body.value}) const userHasAccess = await metaObject.userHasAccess(userid) diff --git a/src/pages/api/users/info.js b/src/pages/api/users/info.js index 8e4fa85..fe2a2c0 100644 --- a/src/pages/api/users/info.js +++ b/src/pages/api/users/info.js @@ -1,14 +1,20 @@ import { User } from "@/helpers/api/classes/User" import { getICS } from "@/helpers/api/ical" -import { middleWareForAuthorisation } from "@/helpers/api/user" +import { getUserIDFromLogin, middleWareForAuthorisation } from "@/helpers/api/user" import { varNotEmpty } from "@/helpers/general" import moment from "moment" export default async function handler(req, res) { if (req.method === 'GET') { - if(req.headers.authorization!=null && await middleWareForAuthorisation(req.headers.authorization)) + if(await middleWareForAuthorisation(req,res)) { - var userid=await User.idFromAuthorisation(req.headers.authorization) + // var userid=await User.idFromAuthorisation(req.headers.authorization) + var userid = await getUserIDFromLogin(req, res) + if(userid==null){ + return res.status(401).json({ success: false, data: { message: 'PLEASE_LOGIN'} }) + + } + var userObj = new User(userid) var userInfo = await userObj.getInfo() res.status(200).json( {success: true, data: {message: userInfo}}) diff --git a/src/pages/api/users/register.js b/src/pages/api/users/register.js index 0381919..1bd8b2b 100644 --- a/src/pages/api/users/register.js +++ b/src/pages/api/users/register.js @@ -26,6 +26,8 @@ export default async function handler(req, res) { { //User is not in db. Register user. var response = await insertUserIntoDB(req.body.username, req.body.password, req.body.email) + + console.log("response" ,response) if(response){ res.status(200).json({ success: response ,data: {message: "USER_INSERT_OK"} }) diff --git a/src/pages/calendar/view.tsx b/src/pages/calendar/view.tsx new file mode 100644 index 0000000..416cfc9 --- /dev/null +++ b/src/pages/calendar/view.tsx @@ -0,0 +1,35 @@ +import CalendarView from "@/components/page/CalendarViewPage/CalendarView"; +import { checkLogin_InBuilt } from "@/helpers/frontend/user"; +import { nextAuthEnabled } from "@/helpers/thirdparty/nextAuth"; +import { signIn, useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import { useEffect } from "react"; + + +export default function CalendarViewPage(){ + const { data: session, status } = useSession() + const router = useRouter() + + useEffect(() =>{ + + if(nextAuthEnabled()){ + if (status=="unauthenticated" ) { + signIn() + } + }else{ + // Check login using inbuilt function. + + checkLogin_InBuilt(router, "/calendar/view") + } + }, [status,router]) + + + + + + return( + <> + + + ) +} \ No newline at end of file diff --git a/src/pages/filters/manage.tsx b/src/pages/filters/manage.tsx new file mode 100644 index 0000000..46404cc --- /dev/null +++ b/src/pages/filters/manage.tsx @@ -0,0 +1,35 @@ +import CalendarView from "@/components/page/CalendarViewPage/CalendarView"; +import ManageFilters from "@/components/page/ManageFiltersPage/ManageFilters"; +import { checkLogin_InBuilt } from "@/helpers/frontend/user"; +import { nextAuthEnabled } from "@/helpers/thirdparty/nextAuth"; +import { signIn, useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import { useEffect } from "react"; + + +export default function ManageViewPage(){ + const { data: session, status } = useSession() + const router = useRouter() + + useEffect(() =>{ + if(nextAuthEnabled()){ + if (status=="unauthenticated" ) { + signIn() + } + }else{ + // Check login using inbuilt function. + + checkLogin_InBuilt(router, "/filters/manage") + } + }, [status, router]) + + + + + + return( + <> + + + ) +} \ No newline at end of file diff --git a/src/pages/index.js b/src/pages/index.js index 2d77017..518b924 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,46 +1,67 @@ import Head from 'next/head' -import TaskList from '@/components/tasks/TaskList' -import AppBarGeneric from '@/components/common/AppBarGeneric' -import { Col, Row } from 'react-bootstrap' -import { getTodaysDateUnixTimeStamp, varNotEmpty } from '@/helpers/general' -import DashboardView from '@/components/fullcalendar/DashboardView' -import AddTask from '@/components/common/AddTask/AddTask' -import { PRIMARY_COLOUR, SECONDARY_COLOUR } from '@/config/style' -import { Component, useEffect, useState } from 'react' +import AppBarGeneric from '@/components/common/AppBar' +import { useEffect, useState, useRef } from 'react' import { getI18nObject } from '@/helpers/frontend/general' -import { MYDAY_LABEL } from '@/config/constants' -import Offcanvas from 'react-bootstrap/Offcanvas'; -import { AiOutlineMenuUnfold } from 'react-icons/ai' -import Script from 'next/script' -import HomeTasks from '@/components/Home/HomeTasks/HomeTasks' import CombinedView from '@/components/page/CombinedView' -import { Loading } from '@/components/common/Loading' +import { useSession, signIn } from "next-auth/react" +import { nextAuthEnabled } from '@/helpers/thirdparty/nextAuth' +import { checkLogin_InBuilt, logoutUser_withRedirect } from '@/helpers/frontend/user' +import { varNotEmpty } from '@/helpers/general' +import { useRouter } from 'next/router' const i18next = getI18nObject() - export default function HomePage() { + const { data: session, status } = useSession() const [updated, setUpdated]=useState('') const [isSyncing, setIsSyncing] = useState(false) - const onSynComplete = () =>{ var updated = Math.floor(Date.now() / 1000) setUpdated(updated) } - const [finalOutput, setFinalOutput] =useState() + //const [finalOutput, setFinalOutput] =useState() + // useEffect(()=>{ + + + // // if(!loginChecked.current){ + // // loginChecked.current=true + // // const checkAuth = async() =>{ + // // const auth = await isUserLoggedIn() + // // if(auth){ + // // setUserAuthenticated(true) + // // } + // // } + // // checkAuth() + // // } + + // // }, [userAuthenticated]) + const router = useRouter() + + useEffect(() =>{ + if(nextAuthEnabled()){ + if (status=="unauthenticated" ) { + signIn() + } + }else{ + // Check login using inbuilt function. + checkLogin_InBuilt(router) + } + }, [status, router]) + + + + var finalOutput = () - useEffect(()=>{ - }) return( <> - {i18next.t("APP_NAME_TITLE")} - {i18next.t("TASKS")} + {i18next.t("APP_NAME_TITLE")} - {i18next.t("HOME")}
- {finalOutput} + {finalOutput}
diff --git a/src/pages/labels/manage.tsx b/src/pages/labels/manage.tsx new file mode 100644 index 0000000..4c42a5d --- /dev/null +++ b/src/pages/labels/manage.tsx @@ -0,0 +1,35 @@ +import ManageLabels from "@/components/page/MangerLabelsPage/ManageLabels"; +import { checkLogin_InBuilt } from "@/helpers/frontend/user"; +import { nextAuthEnabled } from "@/helpers/thirdparty/nextAuth"; +import { signIn, useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import { useEffect } from "react"; + + +export default function ManageLabelsPage(){ + const { data: session, status } = useSession() + const router = useRouter() + + useEffect(() =>{ + + if(nextAuthEnabled()){ + if (status=="unauthenticated" ) { + signIn() + } + }else{ + // Check login using inbuilt function. + + checkLogin_InBuilt(router, "/labels/manage") + } + }, [status, router]) + + + + + + return( + <> + + + ) +} \ No newline at end of file diff --git a/src/pages/tasks/list.tsx b/src/pages/tasks/list.tsx new file mode 100644 index 0000000..d6e5b95 --- /dev/null +++ b/src/pages/tasks/list.tsx @@ -0,0 +1,35 @@ +import TaskViewList from "@/components/page/TaskViewPage/TaskViewList"; +import { checkLogin_InBuilt } from "@/helpers/frontend/user"; +import { nextAuthEnabled } from "@/helpers/thirdparty/nextAuth"; +import { signIn, useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import { useEffect } from "react"; + + +export default function TaskListPage(){ + const { data: session, status } = useSession() + const router = useRouter() + + useEffect(() =>{ + + if(nextAuthEnabled()){ + if (status=="unauthenticated" ) { + signIn() + } + }else{ + // Check login using inbuilt function. + + checkLogin_InBuilt(router, "/tasks/list") + } + }, [status,router]) + + + + + + return( + <> + + + ) +} \ No newline at end of file