Skip to content

Commit

Permalink
Merge pull request #674 from ChicagoWorldcon/PLAN-543-airmeet
Browse files Browse the repository at this point in the history
PLAN-543 Airmeet Integration
  • Loading branch information
Gailbear authored Aug 21, 2022
2 parents 14c5244 + c5f4f64 commit a525038
Show file tree
Hide file tree
Showing 31 changed files with 720 additions and 20 deletions.
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ gem 'truemail'
# This is needed to run the migrations from id to uuid for primary keys
gem 'webdack-uuid_migration'

# for integrations!
gem "httparty"
gem "json-diff"

group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
Expand Down
10 changes: 10 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,17 @@ GEM
guard-compat (~> 1.0)
multi_json (~> 1.8)
http_parser.rb (0.8.0)
httparty (0.20.0)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
io-wait (0.2.3)
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
json (2.6.2)
json-diff (0.4.1)
jsonapi-renderer (0.2.2)
jsonapi-serializer (2.2.0)
activesupport (>= 4.2)
Expand Down Expand Up @@ -190,11 +194,15 @@ GEM
marcel (1.0.2)
matrix (0.4.2)
method_source (1.0.0)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2022.0105)
mini_mime (1.1.2)
mini_portile2 (2.8.0)
minitest (5.16.3)
msgpack (1.5.4)
multi_json (1.15.0)
multi_xml (0.6.0)
nenv (0.3.0)
nilify_blanks (1.4.0)
activerecord (>= 4.0.0)
Expand Down Expand Up @@ -426,8 +434,10 @@ DEPENDENCIES
fast_excel
guard
guard-livereload
httparty
io-wait
jbuilder (~> 2.7)
json-diff
jsonapi-serializer
jsonapi.rb
kaminari
Expand Down
28 changes: 28 additions & 0 deletions app/controllers/integrations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class IntegrationsController < ResourceController
SERIALIZER_CLASS = 'IntegrationSerializer'.freeze
POLICY_CLASS = 'IntegrationPolicy'.freeze

def airmeet
authorize model_class, policy_class: policy_class

airmeet = Integration.find_by({name: 'airmeet'})

render json: serializer_class.new(airmeet,
{
include: serializer_includes,
params: {domain: "#{request.base_url}"}
}
).serializable_hash(),
content_type: 'application/json'
end

def allowed_params
%i[
id
name
lock_version
config
]
end

end
4 changes: 3 additions & 1 deletion app/controllers/published_sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
class PublishedSessionsController < ResourceController
# TBD
SERIALIZER_CLASS = 'PublishedSessionSerializer'.freeze
POLICY_CLASS = 'PublishedSessionPolicy'.freeze
#
end
2 changes: 2 additions & 0 deletions app/helpers/integrations_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module IntegrationsHelper
end
15 changes: 10 additions & 5 deletions app/javascript/administration/admin_component.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
ref="configurations-manager"
></configurations-manager>
</admin-accordion>
<admin-accordion id="integration-accordion" title="Integration Settings">
<integration-settings></integration-settings>
</admin-accordion>
<admin-accordion id="agreements-accordion" title="Agreements" @show="showAgreements">
<agreement-manager
model="agreement"
Expand All @@ -63,12 +66,13 @@
<script>
import AdminAccordion from './admin_accordion.vue'
import PersonAdd from '../people/person_add.vue';
import ChangeUserConventionRoles from './change-user-con-roles';
import MailingsManager from '../mailings/mailings_manager';
import ConfigurationsManager from '../configurations/configurations_manager';
import ChangeUserConventionRoles from './change-user-con-roles.vue';
import MailingsManager from '../mailings/mailings_manager.vue';
import ConfigurationsManager from '../configurations/configurations_manager.vue';
import SheetImporterVue from '../components/sheet_importer_vue.vue';
import AgreementManager from "@/agreements/agreement_manager";
import AgreementManager from "@/agreements/agreement_manager.vue";
import ScheduleSettings from "@/schedule/schedule_settings.vue";
import IntegrationSettings from "@/integrations/integration_settings.vue"
export default {
components: {
Expand All @@ -79,7 +83,8 @@ export default {
SheetImporterVue,
MailingsManager,
ConfigurationsManager,
ScheduleSettings
ScheduleSettings,
IntegrationSettings,
},
name: 'AdminComponent',
data: () => ({
Expand Down
114 changes: 114 additions & 0 deletions app/javascript/airmeet/airmeet_settings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<template>
<div class="container-fluid">
<div class="row">
<div class="column">
<h4 class="mt-3">Configuration</h4>
<b-form-group label="Airmeet ID">
<b-form-input type="text" v-model="airmeet_id" @blur="patchAirmeetConfig()"></b-form-input>
</b-form-group>
<b-form-group label="Airmeet Host Email">
<b-form-input type="text" v-model="airmeet_host" @blur="patchAirmeetConfig()"></b-form-input>
</b-form-group>
<h4 class="mt-5">Room Hosts Setup</h4>
<b-form inline @submit.prevent="addAirmeetRoom($event)" class="mb-5 mt-3">
<b-form-select name="room" :options="nonAirmeetRoomOptions" :value="null"></b-form-select>
<b-input type="text" name="roomHostEmail" placeholder="Room Host Email"></b-input>
<b-button type="submit">Add Airmeet Room</b-button>
</b-form>
<div class="border">
<b-table :fields="airmeetRoomFields" :items="airmeetRooms" sticky-header class="mb-0">
<template #cell(room_host_email)="{ item }">
<b-input type="text" v-model="item.integrations.airmeet.room_host_email" @blur="save(item)"></b-input>
</template>
</b-table>
</div>
</div>
</div>
</div>
</template>

<script>
import { modelMixinNoProp } from '@/mixins'
import { FETCH_AIRMEET_INTEGRATION, integrationModel, SET_AIRMEET_INTEGRATION } from '@/store/integration.store'
import { PATCH_FIELDS, SAVE } from '@/store/model.store'
import { mapState, mapActions, mapMutations } from 'vuex';
import toastMixin from '@/shared/toast-mixin';
export default {
name: "AirmeetSettings",
mixins: [
modelMixinNoProp,
toastMixin
],
data: () => ({
airmeetRoomFields: ['name', 'room_host_email'],
model: 'room'
}),
computed: {
...mapState(['airmeet']),
airmeetRooms() {
return this.collection.filter(r => r.integrations?.airmeet)
},
nonAirmeetRoomOptions() {
return [{text: "Select a room", value: null, disabled: true}, ...this.collection.filter(r => !r.integrations?.airmeet).map(r => ({
text: r.name,
value: r.id
}))]
},
airmeet_id: {
get() {
return this.airmeet?.config?.airmeet_id
},
set(val) {
if(this.airmeet?.config) {
this.airmeet.config.airmeet_id = val;
}
}
},
airmeet_host: {
get() {
return this.airmeet?.config?.airmeet_host
},
set(val) {
if(this.airmeet?.config) {
this.airmeet.config.airmeet_host = val;
}
}
}
},
methods: {
...mapMutations({
setAirmeetInfo: SET_AIRMEET_INTEGRATION,
}),
...mapActions({
fetchAirmeetInfo: FETCH_AIRMEET_INTEGRATION,
patchModel: PATCH_FIELDS
}),
addAirmeetRoom($event) {
const roomId = $event.target.elements.room.value;
const roomHostEmail = $event.target.elements.roomHostEmail.value;
const room = this.collection.find(r => r.id === roomId);
room.integrations ||= {}
room.integrations.airmeet ||= {}
room.integrations.airmeet.room_host_email = roomHostEmail;
this.save(room);
},
patchAirmeetConfig() {
this.toastPromise(new Promise((res, rej) => {
this.patchModel({model: integrationModel, item: this.airmeet, fields: ['config'], selected: false}).then((data) => {
this.setAirmeetInfo(data);
res(data);
}).catch(rej);
}), "Airmeet integration successfully updated.")
}
},
mounted() {
this.fetch();
this.fetchAirmeetInfo();
}
}
</script>
<style>
</style>
28 changes: 28 additions & 0 deletions app/javascript/integrations/integration_settings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<div class="container-fluid">
<div class="row">
<div class="column">
<b-tabs>
<b-tab title="Airmeet">
<airmeet-settings></airmeet-settings>
</b-tab>
</b-tabs>
</div>
</div>
</div>
</template>

<script>
import AirmeetSettings from '@/airmeet/airmeet_settings.vue'
export default {
name: "IntegrationSettings",
components: {
AirmeetSettings
}
}
</script>

<style>
</style>
6 changes: 6 additions & 0 deletions app/javascript/people/person_tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
<b-tab title="Admin" lazy v-if="currentUserIsAdmin || currentUserIsStaff" :active="tab === 'admin'">
<people-admin-tab></people-admin-tab>
</b-tab>
<b-tab title="Integrations" lazy v-if="currentUserIsAdmin" :active="tab === 'integrations'">
<pre>{{JSON.stringify(person.integrations, undefined, 2)}}</pre>
</b-tab>
<b-tab title="Surveys" disabled lazy>
</b-tab>
</b-tabs>
Expand Down Expand Up @@ -132,6 +135,9 @@ export default {
baseTabs.push('email');
baseTabs.push('admin');
}
if(this.currentUserIsAdmin) {
baseTabs.push('integrations');
}
return baseTabs;
},
person() {
Expand Down
21 changes: 18 additions & 3 deletions app/javascript/sessions/session_tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
<b-tab title="Notes" :active="tab === 'notes'">
<session-notes></session-notes>
</b-tab>
<b-tab title="Integrations" v-if="currentUserIsAdmin" :active="tab === 'integrations'">
<pre>{{JSON.stringify(published_session.integrations, undefined, 2)}}</pre>
</b-tab>
</b-tabs>
</div>
</template>
Expand All @@ -48,6 +51,8 @@ import SessionSchedule from './session_schedule';
import SessionConflicts from '../conflicts/session_conflicts.vue'
import { sessionConflictModel } from '@/store/session_conflict.store'
import settingsMixin from "@/store/settings.mixin";
import { personSessionMixin } from '@/mixins';
import { publishedSessionModel } from '@/store/published_session.store';
export default {
name: "SessionTabs",
Expand All @@ -65,16 +70,20 @@ export default {
},
mixins: [
modelUtilsMixin,
settingsMixin
settingsMixin,
personSessionMixin
],
data: () => ({
sessionAssignmentModel,
sessionConflictModel
sessionConflictModel,
}),
computed: {
session() {
return this.selected_model(sessionModel);
},
published_session() {
return this.selected_model(publishedSessionModel) || {};
},
assignmentFilter() {
let filter = {
"op": "all",
Expand Down Expand Up @@ -120,6 +129,9 @@ export default {
case 4:
path = `notes/${this.id}`;
break;
case 5:
path = `integrations/${this.id}`
break;
}
// console.debug("****** Path:", path)
// change the router path to match the current tab
Expand All @@ -138,7 +150,10 @@ export default {
(obj) => {
this.select_model(sessionModel, obj);
}
)
),
this.fetch_model_by_id(publishedSessionModel, this.id).then( (obj) => {
this.select_model(publishedSessionModel, obj)
})
}
}
</script>
Expand Down
28 changes: 28 additions & 0 deletions app/javascript/store/integration.store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { FETCH } from "./model.store"

export const integrationModel = 'integration'

export const integrationEndpoints = {
[integrationModel]: 'integration'
}

export const FETCH_AIRMEET_INTEGRATION = 'FETCH AIRMEET INTEGRATION'
export const SET_AIRMEET_INTEGRATION = 'SET AIRMEET INTEGRATION'

export const integrationStore = {
state: {
airmeet: {}
},
mutations: {
[SET_AIRMEET_INTEGRATION] (state, integration) {
state.airmeet = integration;
}
},
actions: {
[FETCH_AIRMEET_INTEGRATION] ({dispatch, commit}) {
dispatch(FETCH, {url: 'integration/airmeet'}).then(data => {
commit(SET_AIRMEET_INTEGRATION, data);
})
}
}
}
Loading

0 comments on commit a525038

Please sign in to comment.