From 935380f0877d99d72da31deaac7a662ab0cbc395 Mon Sep 17 00:00:00 2001
From: Will Hunt <half-shot@molrams.com>
Date: Sun, 26 Mar 2017 04:58:13 +0100
Subject: [PATCH] Update DiscordStore functions with v3 changes.

---
 config/config.sample.yaml |  2 ++
 src/clientfactory.ts      | 56 +++++++++++++++++----------------
 src/dbschema/v3.ts        | 10 +++---
 src/store.ts              | 65 ++++++++++++++++++++++++++-------------
 4 files changed, 82 insertions(+), 51 deletions(-)

diff --git a/config/config.sample.yaml b/config/config.sample.yaml
index af22a18..16c4883 100644
--- a/config/config.sample.yaml
+++ b/config/config.sample.yaml
@@ -7,3 +7,5 @@ auth:
   botToken: "foobar"
 logging:
   level: "warn" #silly, verbose, info, http, warn, error
+database:
+  filename: "discord.db"
diff --git a/src/clientfactory.ts b/src/clientfactory.ts
index 816dacb..6589a60 100644
--- a/src/clientfactory.ts
+++ b/src/clientfactory.ts
@@ -34,32 +34,36 @@ export class DiscordClientFactory {
   }
 
   public getClient(userId?: string): Promise<any> {
-    let client;
-    if (userId) {
-      if (this.clients.has(userId)) {
-        log.verbose("ClientFactory", "Returning cached user client.");
-        return Promise.resolve(this.clients.get(userId));
-      }
-      return this.store.get_user_token(userId).then((token) => {
-        if (token === null) {
-          return Promise.resolve(this.botClient);
-        }
-        client = Bluebird.promisifyAll(new Client({
-          fetchAllMembers: true,
-          sync: true,
-          messageCacheLifetime: 5,
-        }));
-        log.verbose("ClientFactory", "Got user token. Logging in...");
-        return client.login(token).then(() => {
-          log.verbose("ClientFactory", "Logged in. Storing ", userId);
-          this.clients.set(userId, client);
-          return Promise.resolve(client);
-        }).catch((err) => {
-          log.warn("ClientFactory", `Could not log ${userId} in.`, err);
-        });
-      });
-      // Get from cache
+    if (userId == null) {
+      return Promise.resolve(this.botClient);
+    }
+    return Bluebird.coroutine(this._getClient.bind(this))(userId);
+  }
+
+  private * _getClient(userId: string): any {
+    if (this.clients.has(userId)) {
+      log.verbose("ClientFactory", "Returning cached user client.");
+      return this.clients.get(userId);
+    }
+    const discordIds = yield this.store.get_user_discord_ids(userId);
+    if (discordIds.length === 0) {
+      return Promise.resolve(this.botClient);
+    }
+    // TODO: Select a profile based on preference, not the first one.
+    const token = yield this.store.get_token(discordIds[0]);
+    const client: any = Bluebird.promisifyAll(new Client({
+      fetchAllMembers: true,
+      sync: true,
+      messageCacheLifetime: 5,
+    }));
+    log.verbose("ClientFactory", "Got user token. Logging in...");
+    try {
+      yield client.login(token);
+      log.verbose("ClientFactory", "Logged in. Storing ", userId);
+      this.clients.set(userId, client);
+      return client;
+    } catch (err) {
+      log.warn("ClientFactory", `Could not log ${userId} in.`, err);
     }
-    return Promise.resolve(this.botClient);
   }
 }
diff --git a/src/dbschema/v3.ts b/src/dbschema/v3.ts
index 206d5d9..b7db4b9 100644
--- a/src/dbschema/v3.ts
+++ b/src/dbschema/v3.ts
@@ -11,13 +11,15 @@ export class Schema implements IDbSchema {
   public run(store: DiscordStore): Promise<null> {
     const promise = Promise.all([store.create_table(`
       CREATE TABLE user_id_discord_id (
-        discord_id	TEXT UNIQUE NOT NULL,
-        user_id TEXT UNIQUE NOT NULL
+        discord_id TEXT NOT NULL,
+        user_id TEXT NOT NULL,
+        PRIMARY KEY(discord_id, user_id)
       );`, "user_id_discord_id"),
       store.create_table(`
       CREATE TABLE discord_id_token (
         discord_id TEXT UNIQUE NOT NULL,
-        token	TEXT NOT NULL
+        token	TEXT NOT NULL,
+        PRIMARY KEY(discord_id)
       );`, "discord_id_token",
     )]);
     return promise.then(() => {
@@ -59,7 +61,7 @@ export class Schema implements IDbSchema {
           log.info("SchemaV3", "Dropping %s from database due to an invalid token.");
           return null;
         }).then((dId) => {
-          if(dId === null) {
+          if (dId === null) {
             return null;
           }
           discordId = dId;
diff --git a/src/store.ts b/src/store.ts
index 4b091ae..770a735 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -92,12 +92,16 @@ export class DiscordStore {
     this.db.close();
   }
 
-  public set_user_token(userId: string, token: string) {
+  public add_user_token(userId: string, discordId: string, token: string) {
     log.silly("SQL", "set_user_token => %s", userId);
     return this.db.runAsync(
-      `REPLACE INTO user_tokens (userId,token) VALUES ($id,$token);`
+      `
+      INSERT INTO user_id_discord_id (user_id,discord_id) VALUES ($userId,$discordId);
+      INSERT INTO discord_id_token (discord_id,token) VALUES ($discordId,$token);
+      `
     , {
-      $id: userId,
+      $userId: userId,
+      $discordId: discordId,
       $token: token,
     }).catch( (err) => {
       log.error("TwitDB", "Error storing user token %s", err);
@@ -105,32 +109,53 @@ export class DiscordStore {
     });
   }
 
-  public delete_user_token(userId: string) {
-    log.silly("SQL", "delete_user_token => %s", userId);
-    return this.db.runAsync(
-      `DELETE FROM user_tokens WHERE userId = $id;`
+  public delete_user_token(discordId: string) {
+    log.silly("SQL", "delete_user_token => %s", discordId);
+    return this.db.execAsync(
+      `
+      DELETE FROM user_id_discord_id WHERE discord_id = $id;
+      DELETE FROM discord_id_token WHERE discord_id = $id;
+      `
     , {
-      $id: userId,
+      $id: discordId,
     }).catch( (err) => {
       log.error("TwitDB", "Error deleting user token %s", err);
       throw err;
     });
   }
 
-  public get_user_token(userId: string): Promise<string> {
-    log.silly("SQL", "get_user_token => %s", userId);
+  public get_user_discord_ids(userId: string): Promise<string> {
+    log.silly("SQL", "get_user_discord_ids => %s", userId);
     return this.db.getAsync(
       `
-      SELECT token
-      FROM user_tokens
-      WHERE user_tokens.userId = $id;
+      SELECT discord_id
+      FROM user_id_discord_id
+      WHERE user_id = $userId
+      `, {
+        $userId: userId,
+      },
+    ).then( (rows) => {
+      return rows.map((row) => { return row.discord_id; });
+    }).catch( (err) => {
+      log.error("TwitDB", "Error getting discord ids  %s", err.Error);
+      throw err;
+    });
+  }
+
+  public get_token(discordId: string): Promise<string> {
+    log.silly("SQL", "discord_id_token => %s", discordId);
+    return this.db.getAsync(
       `
-    , {
-      $id: userId,
-    }).then( (row) => {
+      SELECT token
+      FROM discord_id_token
+      WHERE discord_id = $discordId
+      `, {
+        $discordId: discordId,
+      },
+    ).then( (row) => {
       return row !== undefined ? row.token : null;
     }).catch( (err) => {
-      log.error("TwitDB", "Error getting user token  %s", err.Error);
+      log.error("TwitDB", "Error getting discord ids  %s", err.Error);
       throw err;
     });
   }
@@ -166,20 +191,18 @@ export class DiscordStore {
       $discordId: discordId,
       $discordChannel: discordChannel,
       $roomId: roomId,
-    }).then( () => {
-      return
     }).catch( (err) => {
       log.error("TwitDB", "Error executing set_dm_room query  %s", err.Error);
       throw err;
     });
   }
 
-  public get_users_tokens(): Promise<any> {
+  public get_all_user_discord_ids(): Promise<any> {
     log.silly("SQL", "get_users_tokens");
     return this.db.allAsync(
       `
       SELECT *
-      FROM user_tokens
+      FROM get_user_discord_ids
       `,
     ).then( (rows) => {
       return rows;
-- 
GitLab