diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a1166f2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b543bdb --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# ignore modules pulled in from npm +node_modules/ + +# rc-apps package output +dist/ + +# JetBrains IDEs +out/ +.idea/ +.idea_modules/ + +# macOS +.DS_Store +.AppleDouble +.LSOverride +._* +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# vscode extensions +.vscode/ \ No newline at end of file diff --git a/.rcappsconfig b/.rcappsconfig new file mode 100644 index 0000000..f9892ff --- /dev/null +++ b/.rcappsconfig @@ -0,0 +1,19 @@ +{ + "url": "http://localhost:3000", + "username": "", + "password": "", + "ignoredFiles": [ + "**/README.md", + "**/package-lock.json", + "**/package.json", + "**/tslint.json", + "**/tsconfig.json", + "**/*.js", + "**/*.js.map", + "**/*.d.ts", + "**/*.spec.ts", + "**/*.test.ts", + "**/dist/**", + "**/.*" + ] +} \ No newline at end of file diff --git a/BbbMeetApp.ts b/BbbMeetApp.ts new file mode 100644 index 0000000..721a74e --- /dev/null +++ b/BbbMeetApp.ts @@ -0,0 +1,36 @@ +import { + IAppAccessors, + IConfigurationExtend, + ILogger, +} from '@rocket.chat/apps-engine/definition/accessors'; +import { App } from '@rocket.chat/apps-engine/definition/App'; +import { IAppInfo } from '@rocket.chat/apps-engine/definition/metadata'; +import { JoinCommand } from './commands/JoinCommand'; +import { ScheduleMeetCommand } from './commands/ScheduleMeetCommand'; +import { weeklyNotification } from './reminder/processors/weeklyNotification'; +import { AppSettings } from './settings/appsettings'; +import { BbbSettings } from './settings/bbbsettings'; + +export class BbbMeetApp extends App { + + constructor(info: IAppInfo, logger: ILogger, accessors: IAppAccessors) { + super(info, logger, accessors); + } + + protected async extendConfiguration(configuration: IConfigurationExtend): Promise { + + await Promise.all(AppSettings.map((setting) => configuration.settings.provideSetting(setting))); + await Promise.all(BbbSettings.map((setting) => configuration.settings.provideSetting(setting))); + + await configuration.slashCommands.provideSlashCommand(new ScheduleMeetCommand()) + await configuration.slashCommands.provideSlashCommand(new JoinCommand()) + + //Register processors + await configuration.scheduler.registerProcessors([ + { + id : "weeklyreminder", + processor: weeklyNotification, + } + ]); + } +} \ No newline at end of file diff --git a/README.md b/README.md index 767097f..54ec6cc 100644 --- a/README.md +++ b/README.md @@ -1 +1,52 @@ -# Apps.BigBlueButton \ No newline at end of file +# Apps.BigBlueButton + +## 📙 About the App + +An integration of Big Blue Button with Rocket.Chat for conducting a weekly meeting and maintaining the recording video archive. This Rocket.Chat App that will enable users in a channel to join an existing weekly meeting if it is in progress. Or query for recorded meeting videos and view them. + +## 📝 What Apps.BigBlueButton does? + +## 🚀 Steps to run + +- Clone this Repository: + ``` + git clone https://github.com/RocketChat/Apps.BigBlueButton.git + ``` + +- Change the Directory: + ``` + cd Apps.BigBlueButton + ``` + +- Install the required dependencies: + ``` + npm install + ``` + +- Make Sure you have Rocket.Chat server running on your localhost & you have [Rocket.Chat.Apps-cli](https://github.com/RocketChat/Rocket.Chat.Apps-cli) installed, if not : + ``` + npm install -g @rocket.chat/apps-cli + ``` + +- Install the app: + ``` + rc-apps deploy --url http://localhost:3000 --username user_username --password user_password + ``` + Where: + - `http://localhost:3000` is your local server URL (if you are running in another port, change the 3000 to the appropriate port) + - `user_username` is the username of your admin user. + - `user_password` is the password of your admin user. + + For more info refer [this](https://rocket.chat/docs/developer-guides/developing-apps/getting-started/) guide. + +## 👨🏻‍💼 Documentation for reference + +Here are some links to examples and documentation: +- [Rocket.Chat Apps TypeScript Definitions Documentation](https://rocketchat.github.io/Rocket.Chat.Apps-engine/) +- [Rocket.Chat Apps TypeScript Definitions Repository](https://github.com/RocketChat/Rocket.Chat.Apps-engine) +- [Example Rocket.Chat Apps](https://github.com/graywolf336/RocketChatApps) +- Community Forums + - [App Requests](https://forums.rocket.chat/c/rocket-chat-apps/requests) + - [App Guides](https://forums.rocket.chat/c/rocket-chat-apps/guides) + - [Top View of Both Categories](https://forums.rocket.chat/c/rocket-chat-apps) +- [#rocketchat-apps on Open.Rocket.Chat](https://open.rocket.chat/channel/rocketchat-apps) \ No newline at end of file diff --git a/SHA1/sha1.ts b/SHA1/sha1.ts new file mode 100644 index 0000000..2869c8c --- /dev/null +++ b/SHA1/sha1.ts @@ -0,0 +1,203 @@ +export function sha1(str: string): string { + const utf8 = str; + const words32 = stringToWords32(utf8, Endian.Big); + return _sha1(words32, utf8.length * 8); + } + + export function sha1Binary(buffer: ArrayBuffer): string { + const words32 = arrayBufferToWords32(buffer, Endian.Big); + return _sha1(words32, buffer.byteLength * 8); + } + + function _sha1(words32: number[], len: number): string { + const w = new Array(80); + let [a, b, c, d, e]: number[] = [0x67452301, 0xefcdab89, 0x98badcfe, + 0x10325476, 0xc3d2e1f0]; + + words32[len >> 5] |= 0x80 << (24 - len % 32); + words32[((len + 64 >> 9) << 4) + 15] = len; + + for (let i = 0; i < words32.length; i += 16) { + const [h0, h1, h2, h3, h4]: number[] = [a, b, c, d, e]; + + for (let j = 0; j < 80; j++) { + if (j < 16) { + w[j] = words32[i + j]; + } else { + w[j] = rol32(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1); + } + + const [f, k] = fk(j, b, c, d); + const temp = [rol32(a, 5), f, e, k, w[j]].reduce(add32); + [e, d, c, b, a] = [d, c, rol32(b, 30), a, temp]; + } + + [a, b, c, d, e] = [add32(a, h0), add32(b, h1), add32(c, h2), add32(d, h3), add32(e, h4)]; + } + + return byteStringToHexString(words32ToByteString([a, b, c, d, e])); + } + + function add32(a: number, b: number): number { + return add32to64(a, b)[1]; + } + + function add32to64(a: number, b: number): [number, number] { + const low = (a & 0xffff) + (b & 0xffff); + const high = (a >>> 16) + (b >>> 16) + (low >>> 16); + return [high >>> 16, (high << 16) | (low & 0xffff)]; + } + + function add64([ah, al]: [number, number], [bh, bl]: [number, number]): [number, number] { + const [carry, l] = add32to64(al, bl); + const h = add32(add32(ah, bh), carry); + return [h, l]; + } + + function sub32(a: number, b: number): number { + const low = (a & 0xffff) - (b & 0xffff); + const high = (a >> 16) - (b >> 16) + (low >> 16); + return (high << 16) | (low & 0xffff); + } + + // Rotate a 32b number left 'count' position + function rol32(a: number, count: number): number { + return (a << count) | (a >>> (32 - count)); + } + + // Rotate a 64b number left 'count' position + function rol64([hi, lo]: [number, number], count: number): [number, number] { + const h = (hi << count) | (lo >>> (32 - count)); + const l = (lo << count) | (hi >>> (32 - count)); + return [h, l]; + } + + enum Endian { + Little, + Big, + } + + function fk(index: number, b: number, c: number, d: number): [number, number] { + if (index < 20) { + return [(b & c) | (~b & d), 0x5a827999]; + } + + if (index < 40) { + return [b ^ c ^ d, 0x6ed9eba1]; + } + + if (index < 60) { + return [(b & c) | (b & d) | (c & d), 0x8f1bbcdc]; + } + + return [b ^ c ^ d, 0xca62c1d6]; + } + + + function stringToWords32(str: string, endian: Endian): number[] { + const words32 = Array((str.length + 3) >>> 2); + + for (let i = 0; i < words32.length; i++) { + words32[i] = wordAt(str, i * 4, endian); + } + + return words32; + } + + function arrayBufferToWords32(buffer: ArrayBuffer, endian: Endian): number[] { + const words32 = Array((buffer.byteLength + 3) >>> 2); + const view = new Uint8Array(buffer); + for (let i = 0; i < words32.length; i++) { + words32[i] = wordAt(view, i * 4, endian); + } + return words32; + } + + function byteAt(str: string | Uint8Array, index: number): number { + if (typeof str === 'string') { + return index >= str.length ? 0 : str.charCodeAt(index) & 0xff; + } else { + return index >= str.byteLength ? 0 : str[index] & 0xff; + } + } + + function wordAt(str: string | Uint8Array, index: number, endian: Endian): number { + let word = 0; + if (endian === Endian.Big) { + for (let i = 0; i < 4; i++) { + word += byteAt(str, index + i) << (24 - 8 * i); + } + } else { + for (let i = 0; i < 4; i++) { + word += byteAt(str, index + i) << 8 * i; + } + } + return word; + } + + function words32ToByteString(words32: number[]): string { + return words32.reduce((str, word) => str + word32ToByteString(word), ''); + } + + function word32ToByteString(word: number): string { + let str = ''; + for (let i = 0; i < 4; i++) { + str += String.fromCharCode((word >>> 8 * (3 - i)) & 0xff); + } + return str; + } + + function byteStringToHexString(str: string): string { + let hex: string = ''; + for (let i = 0; i < str.length; i++) { + const b = byteAt(str, i); + hex += (b >>> 4).toString(16) + (b & 0x0f).toString(16); + } + return hex.toLowerCase(); + } + + // based on http://www.danvk.org/hex2dec.html (JS can not handle more than +// 56b) + function byteStringToDecString(str: string): string { + let decimal = ''; + let toThePower = '1'; + + for (let i = str.length - 1; i >= 0; i--) { + decimal = addBigInt(decimal, numberTimesBigInt(byteAt(str, i), + toThePower)); + toThePower = numberTimesBigInt(256, toThePower); + } + + return decimal.split('').reverse().join(''); + } + + // x and y decimal, lowest significant digit first + function addBigInt(x: string, y: string): string { + let sum = ''; + const len = Math.max(x.length, y.length); + for (let i = 0, carry = 0; i < len || carry; i++) { + const tmpSum = carry + +(x[i] || 0) + +(y[i] || 0); + if (tmpSum >= 10) { + carry = 1; + sum += tmpSum - 10; + } else { + carry = 0; + sum += tmpSum; + } + } + + return sum; + } + + + function numberTimesBigInt(num: number, b: string): string { + let product = ''; + let bToThePower = b; + for (; num !== 0; num = num >>> 1) { + if (num & 1) product = addBigInt(product, bToThePower); + bToThePower = addBigInt(bToThePower, bToThePower); + } + return product; + } + + //borrowed from https://github.com/angular/angular/blob/master/packages/service-worker/cli/sha1.ts \ No newline at end of file diff --git a/app.json b/app.json new file mode 100644 index 0000000..b0e6bce --- /dev/null +++ b/app.json @@ -0,0 +1,16 @@ +{ + "id": "0dc8312a-f8aa-44cb-bbef-a9e9cf88f243", + "version": "0.0.1", + "requiredApiVersion": "^1.19.0", + "iconFile": "icon.png", + "author": { + "name": "Aswini", + "homepage": "github.com/aswinidev", + "support": "github.com/aswinidev" + }, + "name": "bbb.meet", + "nameSlug": "bbbmeet", + "classFile": "BbbMeetApp.ts", + "description": "A weekly meeting and video archiving system", + "implements": [] +} \ No newline at end of file diff --git a/commands/JoinCommand.ts b/commands/JoinCommand.ts new file mode 100644 index 0000000..b45d411 --- /dev/null +++ b/commands/JoinCommand.ts @@ -0,0 +1,116 @@ +import { IRead, IModify, IHttp, IPersistence, IModifyCreator, IMessageBuilder, IHttpRequest } from "@rocket.chat/apps-engine/definition/accessors"; +import { IMessage } from "@rocket.chat/apps-engine/definition/messages"; +import { IRoom } from "@rocket.chat/apps-engine/definition/rooms"; +import {ISlashCommand, SlashCommandContext} from "@rocket.chat/apps-engine/definition/slashcommands"; +import { BlockBuilder, TextObjectType } from "@rocket.chat/apps-engine/definition/uikit"; +import { IUser } from "@rocket.chat/apps-engine/definition/users"; +import { getMeetingUrl } from "../functions/getMeetingUrl"; + +export class JoinCommand implements ISlashCommand { + public command = "joinmeet"; + public i18nDescription = "Lets you join weekly meetings"; + public providesPreview = false; + public i18nParamsExample = ""; + + public async executor( + context: SlashCommandContext, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence + ): Promise { + const set = read.getEnvironmentReader().getSettings() + const roomstr = await set.getValueById('Meeting_Channels') + const checkroom = async (name: string): Promise => { + const room = await read.getRoomReader().getByName(name) + if (room === undefined) { + return undefined + } + return room.slugifiedName + } + + const rooms : Array = await Promise.all(roomstr.split(',').map(checkroom).filter(Boolean)) + + const commandroom = context.getRoom() + const roomind = rooms.indexOf(commandroom.slugifiedName) + + if(roomind == -1) { + const sender : IUser = (await read.getUserReader().getAppUser()) as IUser + const room : IRoom = context.getRoom() + + const blockBuilder: BlockBuilder = modify.getCreator().getBlockBuilder() + blockBuilder.addSectionBlock({ + text: { + type: TextObjectType.PLAINTEXT, + text: "This Command is not allowed in this channel" + } + }) + + await modify.getNotifier().notifyUser(context.getSender(), { + sender, + room, + blocks: blockBuilder.getBlocks() + }) + return; + } + + const moderatorPW = await set.getValueById('BigBlueButton_moderatorPW') + const attendeePW = await set.getValueById('BigBlueButton_attendeePW') + + const [password]: Array = context.getArguments() + + if(password!==moderatorPW && password!==attendeePW){ + const sender : IUser = (await read.getUserReader().getAppUser()) as IUser + const room : IRoom = context.getRoom() + + const blockBuilder: BlockBuilder = modify.getCreator().getBlockBuilder() + blockBuilder.addSectionBlock({ + text: { + type: TextObjectType.PLAINTEXT, + text: "Wrong Password!" + } + }) + + await modify.getNotifier().notifyUser(context.getSender(), { + sender, + room, + blocks: blockBuilder.getBlocks() + }) + return; + } + + const meeetingURL = await getMeetingUrl(read,password,context,http) + + if(meeetingURL !== undefined){ + const sender : IUser = (await read.getUserReader().getAppUser()) as IUser + const room : IRoom = context.getRoom() + + // The Message is sent with a join url + const blockBuilder: BlockBuilder = modify.getCreator().getBlockBuilder() + blockBuilder.addSectionBlock({ + text: { + type: TextObjectType.MARKDOWN, + text: `Click on the join button below to join the meeting:\n` + } + }) + blockBuilder.addActionsBlock({ + elements: [ + blockBuilder.newButtonElement({ + text: { + type: TextObjectType.PLAINTEXT, + text: 'Join' + }, + url: meeetingURL + }) + ] + }) + + await modify.getNotifier().notifyUser(context.getSender(), { + sender, + room, + blocks: blockBuilder.getBlocks() + }) + } + } +} + diff --git a/commands/ScheduleMeetCommand.ts b/commands/ScheduleMeetCommand.ts new file mode 100644 index 0000000..95c7949 --- /dev/null +++ b/commands/ScheduleMeetCommand.ts @@ -0,0 +1,77 @@ +import { IRead, IModify, IHttp, IPersistence, IModifyCreator, IMessageBuilder, ILogger } from "@rocket.chat/apps-engine/definition/accessors"; +import {ISlashCommand, SlashCommandContext} from "@rocket.chat/apps-engine/definition/slashcommands"; +import { BlockBuilder, TextObjectType } from "@rocket.chat/apps-engine/definition/uikit"; +import { IUser } from "@rocket.chat/apps-engine/definition/users"; + +export class ScheduleMeetCommand implements ISlashCommand { + public command = "schedulemeet"; + public i18nDescription = ""; + public providesPreview = false; + public i18nParamsExample = ""; + public logger : ILogger; + + public async executor( + context: SlashCommandContext, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence + ): Promise { + // await modify.getScheduler().cancelJob(jobId.Reminder) + const set = read.getEnvironmentReader().getSettings() + const roomstr = await set.getValueById('Meeting_Channels') + const checkroom = async (name: string): Promise => { + const room = await read.getRoomReader().getByName(name) + if (room === undefined) { + return undefined + } + return room.slugifiedName + } + + // const rooms : Array = await Promise.all(roomstr.split(',').map(toiroom).filter(Boolean)) + + const rooms : Array = await Promise.all(roomstr.split(',').map(checkroom).filter(Boolean)) + + const commandroom = context.getRoom() + + // if(!rooms.includes(commandroom)){ + // // this.logger.debug(`room is not a meeting channel`) + // return; + // } + + const roomind = rooms.indexOf(commandroom.slugifiedName) + // console.log(rooms) + + const [time, day]: Array = context.getArguments() + var [hour,minute] = time.split(":") + + const hrs = parseInt(hour as string, 10) + const mins = parseInt(minute as string, 10) + + const dayind = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'].indexOf(day) + + // debug code + const sender : IUser = (await read.getUserReader().getAppUser()) as IUser + const blockBuilder: BlockBuilder = modify.getCreator().getBlockBuilder() + blockBuilder.addSectionBlock({ + text: { + type: TextObjectType.PLAINTEXT, + text: `${mins} ${hrs} * * ${dayind}\n ${commandroom.slugifiedName}\n meet${roomind}` + // text: `${rooms[0].slugifiedName} ${commandroom.slugifiedName} ${rooms[0]==commandroom} ${roomind}` + } + }) + + await modify.getNotifier().notifyUser(context.getSender(), { + sender, + room: commandroom, + blocks: blockBuilder.getBlocks() + }) + + await modify.getScheduler().scheduleRecurring({ + id: `meet${roomind}`, + interval: `20 seconds`, + skipImmediate: true, + data: {room: commandroom} + }) + } +} \ No newline at end of file diff --git a/endpoints/webhook.ts b/endpoints/webhook.ts new file mode 100644 index 0000000..8e63da3 --- /dev/null +++ b/endpoints/webhook.ts @@ -0,0 +1,33 @@ +import { HttpStatusCode, IHttp, IMessageBuilder, IModify, IPersistence, IRead } from "@rocket.chat/apps-engine/definition/accessors"; +import { ApiEndpoint, IApiEndpointInfo, IApiRequest, IApiResponse } from "@rocket.chat/apps-engine/definition/api"; +import { IMessage } from "@rocket.chat/apps-engine/definition/messages"; +import { IUser } from "@rocket.chat/apps-engine/definition/users"; + +export class WebhookEndpoint extends ApiEndpoint{ + public path = 'recordingstatus'; + + public async post( + request: IApiRequest, + endpoint: IApiEndpointInfo, + read: IRead, + modify: IModify, + http: IHttp, + persis: IPersistence, + ): Promise { + const set = read.getEnvironmentReader().getSettings() + const room = await set.getValueById('Meeting_Channel') + const sender = (await read.getUserReader().getAppUser()) as IUser + const creator = modify.getCreator() + const messageTemplate: IMessage = { + text: 'Recording is ready', + sender, + room + } + const messageBuilder: IMessageBuilder = creator.startMessage(messageTemplate) + await creator.finish(messageBuilder) + + return { + status: HttpStatusCode.OK + } + } +} \ No newline at end of file diff --git a/enums/settings.ts b/enums/settings.ts new file mode 100644 index 0000000..7ec7b6c --- /dev/null +++ b/enums/settings.ts @@ -0,0 +1,9 @@ +export enum Settings { + MeetingDay = 'Meeting_Day', + MeetingTime = 'Meeting_Time', + MeetingChannel = 'Meeting_Channel', + BbbServerURL = 'BigBlueButton_Server_URL', + BbbSharedSecret = 'BigBlueButton_sharedSecret', + BbbModeratorPW = 'BigBlueButton_moderatorPW', + BbbAttendeePW = 'BigBlueButton_attendeePW', +} \ No newline at end of file diff --git a/functions/getGUID.ts b/functions/getGUID.ts new file mode 100644 index 0000000..c6962ef --- /dev/null +++ b/functions/getGUID.ts @@ -0,0 +1,11 @@ +export function getGUID(): string{ + let d = new Date().getTime(); + const guid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => { + const r = (d + Math.random() * 16) % 16 | 0; + d = Math.floor(d / 16); + return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16); + }); + return guid; +} + +// This is used to generate the meeting id instead of putting it in app settings \ No newline at end of file diff --git a/functions/getMeetingUrl.ts b/functions/getMeetingUrl.ts new file mode 100644 index 0000000..51ad9f6 --- /dev/null +++ b/functions/getMeetingUrl.ts @@ -0,0 +1,35 @@ +import { IHttp, IRead } from "@rocket.chat/apps-engine/definition/accessors"; +import { IRoom } from "@rocket.chat/apps-engine/definition/rooms"; +import { SlashCommandContext } from "@rocket.chat/apps-engine/definition/slashcommands"; +import { IUser } from "@rocket.chat/apps-engine/definition/users"; +import { sha1 } from "../SHA1/sha1"; +import { getGUID } from "./getGUID"; + +export async function getMeetingUrl(read: IRead, password: string, context: SlashCommandContext, http: IHttp): Promise{ + const set = read.getEnvironmentReader().getSettings() + const bbbserver = await set.getValueById('BigBlueButton_Server_URL') + const sharedSecret = await set.getValueById('BigBlueButton_sharedSecret') + const moderatorPW = await set.getValueById('BigBlueButton_moderatorPW') + const attendeePW = await set.getValueById('BigBlueButton_attendeePW') + const meetingId = getGUID() + const meetingName = context.getRoom().slugifiedName + const sender = context.getSender() + + const query = `name=${meetingName}&meetingID=${meetingId}&attendeePW=${attendeePW}&moderatorPW=${moderatorPW}&record=true` + const sha1string = "create" + query + `${sharedSecret}` + const sha = sha1(sha1string) + const url = bbbserver + "/bigbluebutton/api/create?" + query + `&checksum=${sha}` + + //make the create call + const response = await http.get(url) + + if(response.statusCode === 200){ + const joinquery = `fullName=${sender.name}&meetingID=${meetingId}&password=${password}&redirect=true` + const joinsha1string = "join" + joinquery + `${sharedSecret}` + const joinsha1 = sha1(joinsha1string) + const joinurl = bbbserver + "/bigbluebutton/api/join?" + joinquery + `&checksum=${joinsha1}` + return joinurl + } else { + return undefined + } +} \ No newline at end of file diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..b2943b6 Binary files /dev/null and b/icon.png differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..ddda8c0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,409 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", + "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@rocket.chat/apps-engine": { + "version": "1.31.0", + "resolved": "https://registry.npmjs.org/@rocket.chat/apps-engine/-/apps-engine-1.31.0.tgz", + "integrity": "sha512-OAPSjqqFvX8kFgqq0aou05qm1hbIPv0ircUEpimM12DD5lfvmVAFhM5yqRod/DQjgFX2bJDD9NRCgBDRs5L5cw==", + "dev": true, + "requires": { + "adm-zip": "^0.4.9", + "cryptiles": "^4.1.3", + "lodash.clonedeep": "^4.5.0", + "semver": "^5.5.0", + "stack-trace": "0.0.10", + "uuid": "^3.2.1" + } + }, + "@types/node": { + "version": "14.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz", + "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==", + "dev": true + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "boom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", + "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", + "dev": true, + "requires": { + "hoek": "6.x.x" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "cryptiles": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.3.tgz", + "integrity": "sha512-gT9nyTMSUC1JnziQpPbxKGBbUg8VL7Zn2NB4E1cJYvuXdElHrwxrV9bmltZGDzet45zSDGyYceueke1TjynGzw==", + "dev": true, + "requires": { + "boom": "7.x.x" + } + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "typescript": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..8d5e4bd --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "devDependencies": { + "@rocket.chat/apps-engine": "^1.19.0", + "@types/node": "14.14.6", + "tslint": "^5.10.0", + "typescript": "^4.0.5" + } +} diff --git a/reminder/enums/jobid.ts b/reminder/enums/jobid.ts new file mode 100644 index 0000000..83c0150 --- /dev/null +++ b/reminder/enums/jobid.ts @@ -0,0 +1,3 @@ +export enum jobId { + Reminder = 'weeklyreminder' +} \ No newline at end of file diff --git a/reminder/processors/weeklyNotification.ts b/reminder/processors/weeklyNotification.ts new file mode 100644 index 0000000..ee980bd --- /dev/null +++ b/reminder/processors/weeklyNotification.ts @@ -0,0 +1,23 @@ +import { IHttp, IModify, IPersistence, IRead } from "@rocket.chat/apps-engine/definition/accessors" +import { IJobContext } from "@rocket.chat/apps-engine/definition/scheduler" +import { BlockBuilder, TextObjectType } from "@rocket.chat/apps-engine/definition/uikit" +import { IUser } from "@rocket.chat/apps-engine/definition/users" + + +export const weeklyNotification = async (jobContext: IJobContext, read: IRead, modify: IModify, http: IHttp, persis: IPersistence): Promise => { + const block = modify.getCreator().getBlockBuilder() + // this.getLogger().log('Reached Processor') + block.addSectionBlock({ + text: { + type: TextObjectType.PLAINTEXT, + text: "The scheduled weekly meeting is about to start! Join by using the /joinmeet command" + } + }) + const sender: IUser = (await read.getUserReader().getAppUser()) as IUser + const commandroom = jobContext.room + if(commandroom!=undefined){ + await modify.getCreator().finish( + modify.getCreator().startMessage().setSender(sender).addBlocks(block.getBlocks()).setRoom(commandroom) + ) + } +} \ No newline at end of file diff --git a/settings/appsettings.ts b/settings/appsettings.ts new file mode 100644 index 0000000..0255ae2 --- /dev/null +++ b/settings/appsettings.ts @@ -0,0 +1,20 @@ +import { ISetting, SettingType } from "@rocket.chat/apps-engine/definition/settings"; + +export enum Settings { + MeetingDay = 'Meeting_Day', + MeetingTime = 'Meeting_Time', + MeetingChannels = 'Meeting_Channels', + ReminderRole = 'Reminder_Role', +} + +export const AppSettings : Array = [ + { + id: Settings.MeetingChannels, + type: SettingType.STRING, + packageValue: '', + required: true, + public: true, + i18nLabel: 'Meeting Channels', + i18nDescription: 'The Channel in which notifications are to be sent and commands to be usable', + }, +] \ No newline at end of file diff --git a/settings/bbbsettings.ts b/settings/bbbsettings.ts new file mode 100644 index 0000000..244e78d --- /dev/null +++ b/settings/bbbsettings.ts @@ -0,0 +1,49 @@ +import { ISetting, SettingType } from "@rocket.chat/apps-engine/definition/settings"; + +export enum Settings { + BbbServerURL = 'BigBlueButton_Server_URL', + BbbSharedSecret = 'BigBlueButton_sharedSecret', + BbbModeratorPW = 'BigBlueButton_moderatorPW', + BbbAttendeePW = 'BigBlueButton_attendeePW', + BbbMeetingName = 'BigBlueButton_Meeting_Name', + BbbMeetingId = 'BigBlueButton_Meeting_Id' +} + +export const BbbSettings : Array = [ + { + id: Settings.BbbServerURL, + type: SettingType.STRING, + packageValue: '', + required: true, + public: true, + i18nLabel: 'BigBlueButton Server URL', + i18nDescription: 'The Server URL of where the meetings are supposed to be conducted', + }, + { + id: Settings.BbbSharedSecret, + type: SettingType.STRING, + packageValue: '', + required: true, + public: true, + i18nLabel: 'BigBlueButton sharedSecret', + i18nDescription: 'The BigBlueButton API parameter which could be obtained by running bbb-conf --secret', + }, + { + id: Settings.BbbModeratorPW, + type: SettingType.STRING, + packageValue: '', + required: true, + public: true, + i18nLabel: 'BigBlueButton moderatorPW', + i18nDescription: 'The password to let the person join as a moderator of the meeting', + }, + { + id: Settings.BbbAttendeePW, + type: SettingType.STRING, + packageValue: '', + required: true, + public: true, + i18nLabel: 'BigBlueButton attendeePW', + i18nDescription: 'The password to let the person join as an attendee of the meeting', + }, +] \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..3f5d85a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ +"compilerOptions": { + "target": "es2017", + "module": "commonjs", + "moduleResolution": "node", + "declaration": false, + "noImplicitAny": false, + "removeComments": true, + "strictNullChecks": true, + "noImplicitReturns": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + }, +"include": [ + "**/*.ts" + ] +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..b01606a --- /dev/null +++ b/tslint.json @@ -0,0 +1,15 @@ +{ + "extends": "tslint:recommended", + "rules": { + "array-type": [true, "generic"], + "member-access": true, + "no-console": [false], + "no-duplicate-variable": true, + "object-literal-sort-keys": false, + "quotemark": [true, "single"], + "max-line-length": [true, { + "limit": 160, + "ignore-pattern": "^import | *export .*? {" + }] + } +}