diff options
author | bobzel <zzzman@gmail.com> | 2025-06-19 15:34:13 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2025-06-19 15:34:13 -0400 |
commit | 21fb3a555cdd861452e2e54de3d0524e29f2bc08 (patch) | |
tree | 44b93ba0b4f9a85dafdb744ccb11dfe3386f4829 /src/server | |
parent | abdfe5b109f42cd5da4aceef1bd667c8e1f6cbbd (diff) | |
parent | 765c7a3870a1d446622a28b157ab00a4dced2879 (diff) |
Merge branch 'task_nodes_aarav'
Diffstat (limited to 'src/server')
-rw-r--r-- | src/server/ApiManagers/FireflyManager.ts | 11 | ||||
-rw-r--r-- | src/server/ApiManagers/GeneralGoogleManager.ts | 135 | ||||
-rw-r--r-- | src/server/RouteManager.ts | 8 | ||||
-rw-r--r-- | src/server/apis/google/GoogleApiServerUtils.ts | 11 | ||||
-rw-r--r-- | src/server/apis/google/google_project_credentials.json | 8 | ||||
-rw-r--r-- | src/server/authentication/DashUserModel.ts | 14 | ||||
-rw-r--r-- | src/server/authentication/Passport.ts | 6 |
7 files changed, 174 insertions, 19 deletions
diff --git a/src/server/ApiManagers/FireflyManager.ts b/src/server/ApiManagers/FireflyManager.ts index 07ef271a1..6393a1f74 100644 --- a/src/server/ApiManagers/FireflyManager.ts +++ b/src/server/ApiManagers/FireflyManager.ts @@ -23,7 +23,16 @@ export default class FireflyManager extends ApiManager { return undefined; }); - generateImageFromStructure = (prompt: string = 'a realistic illustration of a cat coding', width: number = 2048, height: number = 2048, structureUrl: string, strength: number = 50, styles: string[], styleUrl: string | undefined, variations: number = 4) => + generateImageFromStructure = ( + prompt: string = 'a realistic illustration of a cat coding', + width: number = 2048, + height: number = 2048, + structureUrl: string, + strength: number = 50, + styles: string[], + styleUrl: string | undefined, + variations: number = 4 + ) => this.getBearerToken().then(response => response?.json().then((data: { access_token: string }) => //prettier-ignore diff --git a/src/server/ApiManagers/GeneralGoogleManager.ts b/src/server/ApiManagers/GeneralGoogleManager.ts index 12913b1ef..110701418 100644 --- a/src/server/ApiManagers/GeneralGoogleManager.ts +++ b/src/server/ApiManagers/GeneralGoogleManager.ts @@ -3,6 +3,7 @@ import { Method } from '../RouteManager'; import { GoogleApiServerUtils } from '../apis/google/GoogleApiServerUtils'; import RouteSubscriber from '../RouteSubscriber'; import { Database } from '../database'; +import { google } from 'googleapis'; const EndpointHandlerMap = new Map<GoogleApiServerUtils.Action, GoogleApiServerUtils.ApiRouter>([ ['create', (api, params) => api.create(params)], @@ -61,5 +62,139 @@ export default class GeneralGoogleManager extends ApiManager { res.send(undefined); }, }); + + // Task Creation + register({ + method: Method.POST, + subscription: new RouteSubscriber('googleTasks').add('create'), + secureHandler: async ({ req, res, user }) => { + try { + const auth = await GoogleApiServerUtils.retrieveOAuthClient(user.id); + + if (!auth) { + return res.status(401).send('Google credentials missing or invalid.'); + } + + const tasks = google.tasks({ version: 'v1', auth }); + + const { title, notes, due, status, completed, deleted } = req.body; + const result = await tasks.tasks.insert({ + tasklist: '@default', + requestBody: { title, notes, due, status, completed, deleted }, + }); + + res.status(200).send(result.data); + } catch (err) { + console.error('Google Tasks error:', err); + res.status(500).send('Failed to create task.'); + } + }, + }); + + // Task Update + register({ + method: Method.PATCH, + subscription: new RouteSubscriber('googleTasks').add('taskId'), + // any way to add static params? like /update (this is not very descriptive) + secureHandler: async ({ req, res, user }) => { + try { + const auth = await GoogleApiServerUtils.retrieveOAuthClient(user.id); + + if (!auth) { + return res.status(401).send('Google credentials missing or invalid.'); + } + + const tasks = google.tasks({ version: 'v1', auth }); + + const { taskId } = req.params; + const { title, notes, due, status, completed, deleted } = req.body; + + const result = await tasks.tasks.patch({ + tasklist: '@default', + task: taskId, + requestBody: { title, notes, due, status, completed, deleted}, + }); + + res.status(200).send(result.data); + } catch (err) { + console.error('Google Tasks update error:', err); + res.status(500).send('Failed to update task.'); + } + }, + }); + + // Task Deletion + register({ + method: Method.DELETE, + subscription: new RouteSubscriber('googleTasks').add('taskId'), + secureHandler: async ({ req, res, user }) => { + try { + const auth = await GoogleApiServerUtils.retrieveOAuthClient(user.id); + + if (!auth) { + return res.status(401).send('Google credentials missing or invalid.'); + } + + const tasks = google.tasks({ version: 'v1', auth }); + const { taskId } = req.params; + + await tasks.tasks.delete({ + tasklist: '@default', + task: taskId, + }); + + res.status(200).send({ success: true }); + } catch (err) { + console.error('Google Tasks delete error:', err); + res.status(500).send('Failed to delete task.'); + } + }, + }); + + // Google Account Linking + + register({ + method: Method.GET, + subscription: '/refreshGoogle', + secureHandler: async ({ user, req, res }) => + new Promise<void>(resolve => + GoogleApiServerUtils.processNewUser(user.id, req.query.code as string) + .then(() => res.status(200).send('Google account linked successfully!')) + .catch(err => { + console.error('Failed to process Google code:', err); + res.status(500).send('Error linking Google account'); + }) + .finally(resolve) + ), + }); + + // Task Retrieval + register({ + method: Method.GET, + subscription: new RouteSubscriber('googleTasks').add('taskId'), + secureHandler: async ({ req, res, user }) => { + try { + const auth = await GoogleApiServerUtils.retrieveOAuthClient(user.id); + + if (!auth) { + return res.status(401).send('Google credentials missing or invalid.'); + } + + const tasks = google.tasks({ version: 'v1', auth }); + const { taskId } = req.params; + + const result = await tasks.tasks.get({ + tasklist: '@default', + task: taskId, + }); + + res.status(200).send(result.data); + } catch (err) { + console.error('Google Tasks retrieval error:', err); + res.status(500).send('Failed to retrieve task.'); + } + }, + }); } + } diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts index 2f6cf80b5..c5d70da3d 100644 --- a/src/server/RouteManager.ts +++ b/src/server/RouteManager.ts @@ -8,6 +8,8 @@ import { DashUserModel } from './authentication/DashUserModel'; export enum Method { GET, POST, + PATCH, + DELETE, } export interface CoreArguments { @@ -207,6 +209,12 @@ export default class RouteManager { case Method.POST: this.server.post(route, supervised); break; + case Method.PATCH: + this.server.patch(route, supervised); + break; + case Method.DELETE: + this.server.delete(route, supervised); + break; default: } } diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index 7373df473..ad0f0e580 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -13,7 +13,7 @@ import { GoogleCredentialsLoader } from './CredentialsLoader'; * This is the somewhat overkill list of what Dash requests * from the user. */ -const scope = ['documents.readonly', 'documents', 'presentations', 'presentations.readonly', 'drive', 'drive.file', 'photoslibrary', 'photoslibrary.appendonly', 'photoslibrary.sharing', 'userinfo.profile'].map( +const scope = ['tasks', 'documents.readonly', 'documents', 'presentations', 'presentations.readonly', 'drive', 'drive.file', 'photoslibrary', 'photoslibrary.appendonly', 'photoslibrary.sharing', 'userinfo.profile'].map( relative => `https://www.googleapis.com/auth/${relative}` ); @@ -181,7 +181,7 @@ export namespace GoogleApiServerUtils { * @returns the newly generated url to the authentication landing page */ export function generateAuthenticationUrl(): string { - return worker.generateAuthUrl({ scope, access_type: 'offline' }); + return worker.generateAuthUrl({ scope, access_type: 'offline', prompt: 'consent' }); } /** @@ -203,12 +203,12 @@ export namespace GoogleApiServerUtils { */ export async function processNewUser(userId: string, authenticationCode: string): Promise<EnrichedCredentials> { const credentials = await new Promise<Credentials>((resolve, reject) => { - worker.getToken(authenticationCode, (err, credentials) => { - if (err || !credentials) { + worker.getToken(authenticationCode, (err, creds) => { + if (err || !creds) { reject(err); return; } - resolve(credentials); + resolve(creds); }); }); const enriched = injectUserInfo(credentials); @@ -304,6 +304,7 @@ export namespace GoogleApiServerUtils { const { access_token, expires_in } = await new Promise<{ access_token: string; expires_in: number }>(resolve => { request.post(url, headerParameters).then(response => resolve(JSON.parse(response))); }); + // expires_in is in seconds, but we're building the new expiry date in milliseconds const expiry_date = new Date().getTime() + expires_in * 1000; await Database.Auxiliary.GoogleAccessToken.Update(userId, access_token, expiry_date); diff --git a/src/server/apis/google/google_project_credentials.json b/src/server/apis/google/google_project_credentials.json index 955c5a3c1..438e5157e 100644 --- a/src/server/apis/google/google_project_credentials.json +++ b/src/server/apis/google/google_project_credentials.json @@ -1,11 +1,11 @@ { "installed": { - "client_id": "343179513178-ud6tvmh275r2fq93u9eesrnc66t6akh9.apps.googleusercontent.com", - "project_id": "quickstart-1565056383187", + "client_id": "740987818053-dtflji3hfkn5r9t8ad6jb8740pls8moh.apps.googleusercontent.com", + "project_id": "dash-web-461920", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_secret": "w8KIFSc0MQpmUYHed4qEzn8b", - "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost"] + "client_secret": "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", + "redirect_uris": ["http://localhost:1050/refreshGoogle"] } }
\ No newline at end of file diff --git a/src/server/authentication/DashUserModel.ts b/src/server/authentication/DashUserModel.ts index debeef60c..6fd8dd593 100644 --- a/src/server/authentication/DashUserModel.ts +++ b/src/server/authentication/DashUserModel.ts @@ -2,9 +2,10 @@ import * as bcrypt from 'bcrypt-nodejs'; import * as mongoose from 'mongoose'; import { Utils } from '../../Utils'; -type comparePasswordFunction = (candidatePassword: string, cb: (err: any, isMatch: any) => void) => void; -export type DashUserModel = mongoose.Document & { - email: String; +type comparePasswordFunction = (candidatePassword: string, cb: (err: Error, isMatch: boolean) => void) => void; +type mongooseDocument = { id: string }; // & mongoose.Document; +export type DashUserModel = mongooseDocument & { + email: string; password: string; passwordResetToken?: string; passwordResetExpires?: Date; @@ -65,12 +66,13 @@ const userSchema = new mongoose.Schema( /** * Password hash middleware. */ -userSchema.pre('save', function save(next) { +// eslint-disable-next-line @typescript-eslint/no-explicit-any +userSchema.pre('save', function save(next: any) { const user = this; if (!user.isModified('password')) { return next(); } - bcrypt.genSalt(10, (err: any, salt: string) => { + bcrypt.genSalt(10, (err: Error, salt: string) => { if (err) { return next(err); } @@ -102,7 +104,7 @@ const comparePassword: comparePasswordFunction = function (this: DashUserModel, userSchema.methods.comparePassword = comparePassword; -const User: any = mongoose.model('User', userSchema); +const User = mongoose.model('User', userSchema); export function initializeGuest() { new User({ email: 'guest', diff --git a/src/server/authentication/Passport.ts b/src/server/authentication/Passport.ts index ca9e3058e..a62d38e3e 100644 --- a/src/server/authentication/Passport.ts +++ b/src/server/authentication/Passport.ts @@ -5,13 +5,13 @@ import User, { DashUserModel } from './DashUserModel'; const LocalStrategy = passportLocal.Strategy; passport.serializeUser<any, any>((req, user, done) => { - done(undefined, (user as any)?.id); + done(undefined, (user as DashUserModel)?.id); }); passport.deserializeUser<any, any>((id, done) => { User.findById(id) .exec() - .then((user: any) => done(undefined, user)); + .then((user: DashUserModel) => done(undefined, user)); }); // AUTHENTICATE JUST WITH EMAIL AND PASSWORD @@ -30,6 +30,6 @@ passport.use( }); } }) - .catch((error: any) => done(error)); + .catch((error: Error) => done(error)); }) ); |