amazon-chime-sdk-rails 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +87 -0
- data/.rspec +2 -0
- data/.travis.yml +47 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +25 -0
- data/LICENSE +21 -0
- data/README.md +1109 -0
- data/Rakefile +20 -0
- data/amazon-chime-sdk-rails.gemspec +29 -0
- data/gemfiles/Gemfile.rails-5.0 +25 -0
- data/gemfiles/Gemfile.rails-5.1 +25 -0
- data/gemfiles/Gemfile.rails-5.2 +25 -0
- data/gemfiles/Gemfile.rails-6.0 +25 -0
- data/lib/amazon-chime-sdk-rails.rb +37 -0
- data/lib/chime_sdk/config.rb +90 -0
- data/lib/chime_sdk/controller/attendees.rb +128 -0
- data/lib/chime_sdk/controller/common.rb +202 -0
- data/lib/chime_sdk/controller/meetings.rb +192 -0
- data/lib/chime_sdk/meeting_coordinator.rb +184 -0
- data/lib/chime_sdk/version.rb +4 -0
- data/lib/generators/chime_sdk/controllers_generator.rb +104 -0
- data/lib/generators/chime_sdk/install_generator.rb +27 -0
- data/lib/generators/chime_sdk/js_generator.rb +67 -0
- data/lib/generators/chime_sdk/views_generator.rb +43 -0
- data/lib/generators/templates/chime_sdk.rb +28 -0
- data/lib/generators/templates/controllers/README +35 -0
- data/lib/generators/templates/controllers/meeting_attendees_controller.rb +106 -0
- data/lib/generators/templates/controllers/meetings_controller.rb +146 -0
- data/lib/generators/templates/views/meetings/index.html.erb +27 -0
- data/lib/generators/templates/views/meetings/show.html.erb +136 -0
- data/spec/factories/rooms.rb +5 -0
- data/spec/factories/users.rb +8 -0
- data/spec/generators/controllers_generator_spec.rb +113 -0
- data/spec/generators/install_generator_spec.rb +24 -0
- data/spec/generators/js_generator_spec.rb +26 -0
- data/spec/generators/views_generator_spec.rb +46 -0
- data/spec/rails_app/Rakefile +15 -0
- data/spec/rails_app/app/assets/config/manifest.js +2 -0
- data/spec/rails_app/app/assets/images/.keep +0 -0
- data/spec/rails_app/app/assets/javascripts/.keep +0 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +15 -0
- data/spec/rails_app/app/assets/stylesheets/scaffolds.scss +65 -0
- data/spec/rails_app/app/controllers/api/meeting_attendees_controller.rb +3 -0
- data/spec/rails_app/app/controllers/api/meetings_controller.rb +3 -0
- data/spec/rails_app/app/controllers/api/rooms_controller.rb +3 -0
- data/spec/rails_app/app/controllers/application_controller.rb +11 -0
- data/spec/rails_app/app/controllers/entries_controller.rb +47 -0
- data/spec/rails_app/app/controllers/meeting_attendees_controller.rb +121 -0
- data/spec/rails_app/app/controllers/meetings_controller.rb +162 -0
- data/spec/rails_app/app/controllers/rooms_controller.rb +76 -0
- data/spec/rails_app/app/controllers/spa_controller.rb +6 -0
- data/spec/rails_app/app/javascript/App.vue +50 -0
- data/spec/rails_app/app/javascript/channels/consumer.js +6 -0
- data/spec/rails_app/app/javascript/channels/index.js +5 -0
- data/spec/rails_app/app/javascript/components/DeviseTokenAuth.vue +84 -0
- data/spec/rails_app/app/javascript/components/meetings/Index.vue +100 -0
- data/spec/rails_app/app/javascript/components/meetings/Meeting.vue +178 -0
- data/spec/rails_app/app/javascript/components/rooms/Index.vue +53 -0
- data/spec/rails_app/app/javascript/components/rooms/Show.vue +91 -0
- data/spec/rails_app/app/javascript/packs/application.js +17 -0
- data/spec/rails_app/app/javascript/packs/spa.js +14 -0
- data/spec/rails_app/app/javascript/router/index.js +74 -0
- data/spec/rails_app/app/javascript/store/index.js +37 -0
- data/spec/rails_app/app/models/application_record.rb +3 -0
- data/spec/rails_app/app/models/entry.rb +5 -0
- data/spec/rails_app/app/models/room.rb +12 -0
- data/spec/rails_app/app/models/user.rb +6 -0
- data/spec/rails_app/app/views/devise/registrations/new.html.erb +34 -0
- data/spec/rails_app/app/views/layouts/_header.html.erb +20 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +18 -0
- data/spec/rails_app/app/views/meetings/index.html.erb +28 -0
- data/spec/rails_app/app/views/meetings/show.html.erb +136 -0
- data/spec/rails_app/app/views/rooms/_form.html.erb +22 -0
- data/spec/rails_app/app/views/rooms/_room.json.jbuilder +7 -0
- data/spec/rails_app/app/views/rooms/edit.html.erb +6 -0
- data/spec/rails_app/app/views/rooms/index.html.erb +27 -0
- data/spec/rails_app/app/views/rooms/index.json.jbuilder +1 -0
- data/spec/rails_app/app/views/rooms/new.html.erb +5 -0
- data/spec/rails_app/app/views/rooms/show.html.erb +42 -0
- data/spec/rails_app/app/views/rooms/show.json.jbuilder +1 -0
- data/spec/rails_app/app/views/spa/index.html.erb +1 -0
- data/spec/rails_app/babel.config.js +72 -0
- data/spec/rails_app/bin/bundle +114 -0
- data/spec/rails_app/bin/rails +9 -0
- data/spec/rails_app/bin/rake +9 -0
- data/spec/rails_app/bin/setup +36 -0
- data/spec/rails_app/bin/spring +17 -0
- data/spec/rails_app/bin/webpack +18 -0
- data/spec/rails_app/bin/webpack-dev-server +18 -0
- data/spec/rails_app/bin/yarn +11 -0
- data/spec/rails_app/config.ru +5 -0
- data/spec/rails_app/config/application.rb +21 -0
- data/spec/rails_app/config/boot.rb +4 -0
- data/spec/rails_app/config/cable.yml +10 -0
- data/spec/rails_app/config/credentials.yml.enc +1 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +14 -0
- data/spec/rails_app/config/environments/development.rb +62 -0
- data/spec/rails_app/config/environments/production.rb +112 -0
- data/spec/rails_app/config/environments/test.rb +49 -0
- data/spec/rails_app/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/rails_app/config/initializers/assets.rb +15 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/chime_sdk.rb +28 -0
- data/spec/rails_app/config/initializers/content_security_policy.rb +30 -0
- data/spec/rails_app/config/initializers/cookies_serializer.rb +5 -0
- data/spec/rails_app/config/initializers/devise.rb +311 -0
- data/spec/rails_app/config/initializers/devise_token_auth.rb +60 -0
- data/spec/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/rails_app/config/initializers/inflections.rb +16 -0
- data/spec/rails_app/config/initializers/mime_types.rb +4 -0
- data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_app/config/locales/devise.en.yml +65 -0
- data/spec/rails_app/config/locales/en.yml +33 -0
- data/spec/rails_app/config/puma.rb +38 -0
- data/spec/rails_app/config/routes.rb +24 -0
- data/spec/rails_app/config/secrets.yml +8 -0
- data/spec/rails_app/config/spring.rb +6 -0
- data/spec/rails_app/config/storage.yml +34 -0
- data/spec/rails_app/config/webpack/development.js +5 -0
- data/spec/rails_app/config/webpack/environment.js +7 -0
- data/spec/rails_app/config/webpack/loaders/vue.js +6 -0
- data/spec/rails_app/config/webpack/production.js +5 -0
- data/spec/rails_app/config/webpack/test.js +5 -0
- data/spec/rails_app/config/webpacker.yml +97 -0
- data/spec/rails_app/db/migrate/20200912140231_devise_create_users.rb +45 -0
- data/spec/rails_app/db/migrate/20200912140352_add_tokens_to_users.rb +12 -0
- data/spec/rails_app/db/migrate/20200912140657_create_rooms.rb +9 -0
- data/spec/rails_app/db/migrate/20200912140749_create_entries.rb +10 -0
- data/spec/rails_app/db/schema.rb +49 -0
- data/spec/rails_app/db/seeds.rb +41 -0
- data/spec/rails_app/log/.keep +0 -0
- data/spec/rails_app/package.json +23 -0
- data/spec/rails_app/postcss.config.js +12 -0
- data/spec/rails_app/public/404.html +67 -0
- data/spec/rails_app/public/422.html +67 -0
- data/spec/rails_app/public/500.html +66 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/robots.txt +1 -0
- data/spec/rails_app/tmp/.keep +0 -0
- data/spec/requests/atendees_spec.rb +182 -0
- data/spec/requests/meetings_spec.rb +433 -0
- data/spec/spec_helper.rb +35 -0
- metadata +400 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
// Action Cable provides the framework to deal with WebSockets in Rails.
|
2
|
+
// You can generate new channels where WebSocket features live using the `rails generate channel` command.
|
3
|
+
|
4
|
+
import { createConsumer } from "@rails/actioncable"
|
5
|
+
|
6
|
+
export default createConsumer()
|
@@ -0,0 +1,84 @@
|
|
1
|
+
<template>
|
2
|
+
<div id="login">
|
3
|
+
<h2>Log in</h2>
|
4
|
+
<form class="new_user" @submit.prevent="login">
|
5
|
+
<div class="field">
|
6
|
+
<label for="user_email">Email</label><br />
|
7
|
+
<input v-model="loginParams.email" autofocus="autofocus" autocomplete="email" type="email" value="" name="user[email]" id="user_email" />
|
8
|
+
</div>
|
9
|
+
<div class="field">
|
10
|
+
<label for="user_password">Password</label><br />
|
11
|
+
<input v-model="loginParams.password" autocomplete="current-password" type="password" name="user[password]" id="user_password" />
|
12
|
+
</div>
|
13
|
+
<div class="actions">
|
14
|
+
<input type="submit" name="commit" value="Log in" data-disable-with="Log in" />
|
15
|
+
</div>
|
16
|
+
</form>
|
17
|
+
|
18
|
+
<a href="/users/sign_up">(Sign up)</a><br />
|
19
|
+
</div>
|
20
|
+
</template>
|
21
|
+
|
22
|
+
<script>
|
23
|
+
import axios from 'axios'
|
24
|
+
|
25
|
+
export default {
|
26
|
+
name: 'DeviseTokenAuth',
|
27
|
+
props: {
|
28
|
+
isLogout: {
|
29
|
+
type: Boolean,
|
30
|
+
default: false
|
31
|
+
}
|
32
|
+
},
|
33
|
+
data () {
|
34
|
+
return {
|
35
|
+
loginParams: {
|
36
|
+
email: "",
|
37
|
+
password: ""
|
38
|
+
}
|
39
|
+
}
|
40
|
+
},
|
41
|
+
mounted () {
|
42
|
+
if (this.isLogout) {
|
43
|
+
this.logout();
|
44
|
+
}
|
45
|
+
},
|
46
|
+
methods: {
|
47
|
+
login () {
|
48
|
+
axios
|
49
|
+
.post('/auth/sign_in', { email: this.loginParams.email, password: this.loginParams.password })
|
50
|
+
.then(response => {
|
51
|
+
if (response.status == 200) {
|
52
|
+
let authHeaders = {};
|
53
|
+
for (let authHeader of ['access-token', 'client', 'uid']) {
|
54
|
+
authHeaders[authHeader] = response.headers[authHeader];
|
55
|
+
axios.defaults.headers.common[authHeader] = authHeaders[authHeader];
|
56
|
+
}
|
57
|
+
this.$store.commit('signIn', { user: response.data.data, authHeaders: authHeaders });
|
58
|
+
if (this.$route.query.redirect) {
|
59
|
+
this.$router.push(this.$route.query.redirect);
|
60
|
+
} else {
|
61
|
+
this.$router.push('/');
|
62
|
+
}
|
63
|
+
}
|
64
|
+
})
|
65
|
+
.catch (error => {
|
66
|
+
console.log("Authentication failed");
|
67
|
+
if (error.response.status == 401) {
|
68
|
+
this.$router.go({path: this.$router.currentRoute.path});
|
69
|
+
}
|
70
|
+
})
|
71
|
+
},
|
72
|
+
logout () {
|
73
|
+
for (var authHeader of Object.keys(this.$store.getters.authHeaders)) {
|
74
|
+
delete axios.defaults.headers.common[authHeader];
|
75
|
+
}
|
76
|
+
this.$store.commit('signOut');
|
77
|
+
this.$router.push('/');
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
</script>
|
82
|
+
|
83
|
+
<style scoped>
|
84
|
+
</style>
|
@@ -0,0 +1,100 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<p id="notice">{{ notice }}</p>
|
4
|
+
|
5
|
+
<h1>Meetings by Amazon Chime SDK</h1>
|
6
|
+
|
7
|
+
<table>
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th>Meeting ID</th>
|
11
|
+
<th>External Meeting ID</th>
|
12
|
+
<th>Media Region</th>
|
13
|
+
<th colspan="1"></th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
|
17
|
+
<tbody>
|
18
|
+
<tr v-for="meeting in meetings" :key="`${meeting.Meeting.MeetingId}`">
|
19
|
+
<td><router-link v-bind:to="{ name: 'Meeting', params: { room_id: room_id, meeting_id: meeting.Meeting.MeetingId } }">{{ meeting.Meeting.MeetingId }}</router-link></td>
|
20
|
+
<td>{{ meeting.Meeting.ExternalMeetingId }}</td>
|
21
|
+
<td>{{ meeting.Meeting.MediaRegion }}</td>
|
22
|
+
<td><a href="#" v-on:click="delete_meeting(meeting.Meeting.MeetingId, 'Are you sure?')" data-remote="true">Destroy</a></td>
|
23
|
+
</tr>
|
24
|
+
</tbody>
|
25
|
+
</table>
|
26
|
+
|
27
|
+
<p><a href="#" v-on:click="create_meeting(room_id)" data-remote="true">Create Meeting</a></p>
|
28
|
+
<p><router-link v-bind:to="{ name: 'Room', params: { room_id: room_id } }">Back to Room</router-link></p>
|
29
|
+
</div>
|
30
|
+
</template>
|
31
|
+
|
32
|
+
<script>
|
33
|
+
import axios from 'axios'
|
34
|
+
|
35
|
+
export default {
|
36
|
+
name: 'Meetings',
|
37
|
+
props: {
|
38
|
+
room_id: {
|
39
|
+
required: true
|
40
|
+
},
|
41
|
+
message: String
|
42
|
+
},
|
43
|
+
data () {
|
44
|
+
return {
|
45
|
+
meetings: [],
|
46
|
+
notice: this.message
|
47
|
+
}
|
48
|
+
},
|
49
|
+
mounted () {
|
50
|
+
axios
|
51
|
+
.get(`/rooms/${this.room_id}/meetings`)
|
52
|
+
.then(response => {
|
53
|
+
this.meetings = response.data.meetings;
|
54
|
+
})
|
55
|
+
.catch(error => {
|
56
|
+
if (error.response.status == 403) {
|
57
|
+
this.$router.push({ name: 'Room', params: { room_id: this.room_id, message: error.response.data.notice } });
|
58
|
+
}
|
59
|
+
this.notice = error;
|
60
|
+
})
|
61
|
+
},
|
62
|
+
methods: {
|
63
|
+
create_meeting (room_id) {
|
64
|
+
axios
|
65
|
+
.post(`/rooms/${this.room_id}/meetings`)
|
66
|
+
.then(response => {
|
67
|
+
if (response.status == 201) {
|
68
|
+
let meeting_id = response.data.Meeting.MeetingId;
|
69
|
+
this.$router.push({ name: 'Meeting', params: { room_id: this.room_id, meeting_id: meeting_id, message: `Meeting <${meeting_id}> was successfully created.` } });
|
70
|
+
}
|
71
|
+
})
|
72
|
+
.catch (error => {
|
73
|
+
if (error.response.status == 403) {
|
74
|
+
this.notice = error.response.data.notice;
|
75
|
+
} else {
|
76
|
+
this.notice = error;
|
77
|
+
}
|
78
|
+
})
|
79
|
+
},
|
80
|
+
delete_meeting(meeting_id, confirmation) {
|
81
|
+
if (confirm(confirmation)) {
|
82
|
+
axios
|
83
|
+
.delete(`/rooms/${this.room_id}/meetings/${meeting_id}`)
|
84
|
+
.then(response => {
|
85
|
+
if (response.status == 204) {
|
86
|
+
this.notice = `Meeting <${meeting_id}> was successfully destroyed.`;
|
87
|
+
}
|
88
|
+
})
|
89
|
+
.catch (error => {
|
90
|
+
console.log(error.response);
|
91
|
+
this.notice = error;
|
92
|
+
})
|
93
|
+
}
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
</script>
|
98
|
+
|
99
|
+
<style scoped>
|
100
|
+
</style>
|
@@ -0,0 +1,178 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<p id="notice">{{ notice }}</p>
|
4
|
+
|
5
|
+
<h1>Meeting by Amazon Chime SDK</h1>
|
6
|
+
|
7
|
+
<p><router-link v-bind:to="{ name: 'Meetings', params: { room_id: room_id } }">Show Meetings</router-link></p>
|
8
|
+
|
9
|
+
<div v-if="meeting">
|
10
|
+
<strong>Meeting</strong>
|
11
|
+
<p>
|
12
|
+
Meeting ID : <router-link v-bind:to="{ name: 'Meeting', params: { room_id: room_id, meeting_id: meeting.Meeting.MeetingId } }">{{ meeting.Meeting.MeetingId }}</router-link><br>
|
13
|
+
External Meeting ID : {{ meeting.Meeting.ExternalMeetingId }}<br>
|
14
|
+
Media Region : {{ meeting.Meeting.MediaRegion }}
|
15
|
+
</p>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div v-if="attendee">
|
19
|
+
<strong>Attendee</strong>
|
20
|
+
<p>
|
21
|
+
Attendee ID : <a v-bind:href="`/rooms/${room_id}/meetings/${meeting.Meeting.MeetingId}/attendees/${attendee.Attendee.AttendeeId}`">{{ attendee.Attendee.AttendeeId }}</a><br>
|
22
|
+
External User ID : {{ attendee.Attendee.ExternalUserId }}<br>
|
23
|
+
Application Attendee Name : {{ attendee.Attendee.ApplicationMetadata.User.name }}
|
24
|
+
</p>
|
25
|
+
|
26
|
+
<div id="status">
|
27
|
+
<strong>Status</strong>
|
28
|
+
<div v-if="meetingOnline">
|
29
|
+
<div id="meeting-status">
|
30
|
+
<p>Meeting : Online <input type="button" value="Leave a meeting" v-on:click="leave()"></p>
|
31
|
+
<div id="audio-status">
|
32
|
+
<div v-if="meetingMuted">
|
33
|
+
<p>Audio : Muted <input type="button" value="Unmute" v-on:click="unmute()"></p>
|
34
|
+
</div>
|
35
|
+
<div v-else>
|
36
|
+
<p>Audio : Active <input type="button" value="Mute" v-on:click="mute()"></p>
|
37
|
+
</div>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
<div id="attendee-status">
|
41
|
+
<strong>Present Attendees</strong>
|
42
|
+
<ul>
|
43
|
+
<li v-for="attendeeName in presentAttendees" :key="attendeeName">{{ attendeeName }}</li>
|
44
|
+
</ul>
|
45
|
+
</div>
|
46
|
+
</div>
|
47
|
+
<div v-else>
|
48
|
+
<div id="meeting-status">
|
49
|
+
<p>Meeting : Offline <input type="button" value="Join a meeting" v-on:click="join()"></p>
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
</div>
|
53
|
+
|
54
|
+
<audio id="audio"></audio>
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
</template>
|
58
|
+
|
59
|
+
<script>
|
60
|
+
import axios from 'axios'
|
61
|
+
import {
|
62
|
+
ConsoleLogger,
|
63
|
+
DefaultDeviceController,
|
64
|
+
DefaultMeetingSession,
|
65
|
+
LogLevel,
|
66
|
+
MeetingSessionConfiguration
|
67
|
+
} from 'amazon-chime-sdk-js'
|
68
|
+
|
69
|
+
export default {
|
70
|
+
name: 'Meeting',
|
71
|
+
props: {
|
72
|
+
room_id: {
|
73
|
+
required: true
|
74
|
+
},
|
75
|
+
meeting_id: {
|
76
|
+
required: true
|
77
|
+
},
|
78
|
+
message: String
|
79
|
+
},
|
80
|
+
data () {
|
81
|
+
return {
|
82
|
+
meeting: null,
|
83
|
+
attendee: null,
|
84
|
+
notice: this.message,
|
85
|
+
meetingOnline: false,
|
86
|
+
meetingMuted: false,
|
87
|
+
presentAttendees: []
|
88
|
+
}
|
89
|
+
},
|
90
|
+
mounted () {
|
91
|
+
axios
|
92
|
+
.get(`/rooms/${this.room_id}/meetings/${this.meeting_id}`)
|
93
|
+
.then(response => {
|
94
|
+
this.meeting = { Meeting: response.data.Meeting };
|
95
|
+
this.attendee = { Attendee: response.data.Attendee };
|
96
|
+
|
97
|
+
const logger = new ConsoleLogger('ChimeMeetingLogs', LogLevel.INFO);
|
98
|
+
const deviceController = new DefaultDeviceController(logger);
|
99
|
+
const configuration = new MeetingSessionConfiguration(this.meeting, this.attendee);
|
100
|
+
this.meetingSession = new DefaultMeetingSession(configuration, logger, deviceController);
|
101
|
+
})
|
102
|
+
.catch(error => {
|
103
|
+
if (error.response.status == 404) {
|
104
|
+
this.$router.push({ name: 'Meetings', params: { room_id: this.room_id, message: `${error.response.data.error.message}: ${error.response.data.error.type}` } });
|
105
|
+
} else {
|
106
|
+
this.notice = error;
|
107
|
+
}
|
108
|
+
})
|
109
|
+
},
|
110
|
+
methods: {
|
111
|
+
// Customize this function to extract attendee name to show
|
112
|
+
showApplicationUserName(attendee) {
|
113
|
+
// return attendee.Attendee.AttendeeId;
|
114
|
+
return `${attendee.Attendee.ApplicationMetadata.User.name} (${attendee.Attendee.AttendeeId})`;
|
115
|
+
},
|
116
|
+
async join() {
|
117
|
+
try {
|
118
|
+
const audioInputDevices = await this.meetingSession.audioVideo.listAudioInputDevices();
|
119
|
+
const audioOutputDevices = await this.meetingSession.audioVideo.listAudioOutputDevices();
|
120
|
+
await this.meetingSession.audioVideo.chooseAudioInputDevice(audioInputDevices[0].deviceId);
|
121
|
+
await this.meetingSession.audioVideo.chooseAudioOutputDevice(audioOutputDevices[0].deviceId);
|
122
|
+
} catch (error) {
|
123
|
+
// handle error - unable to acquire audio device perhaps due to permissions blocking
|
124
|
+
console.log(error);
|
125
|
+
}
|
126
|
+
const audioOutputElement = document.getElementById('audio');
|
127
|
+
this.meetingSession.audioVideo.bindAudioElement(audioOutputElement);
|
128
|
+
this.meetingSession.audioVideo.start();
|
129
|
+
this.meetingOnline = true;
|
130
|
+
this.parepareAttendeeStatus();
|
131
|
+
},
|
132
|
+
leave() {
|
133
|
+
this.meetingSession.audioVideo.stop();
|
134
|
+
this.meetingOnline = false;
|
135
|
+
this.meetingMuted = false;
|
136
|
+
this.presentAttendees = [];
|
137
|
+
},
|
138
|
+
mute() {
|
139
|
+
this.meetingSession.audioVideo.realtimeMuteLocalAudio();
|
140
|
+
this.meetingMuted = true;
|
141
|
+
},
|
142
|
+
unmute() {
|
143
|
+
const unmuted = this.meetingSession.audioVideo.realtimeUnmuteLocalAudio();
|
144
|
+
if (unmuted) {
|
145
|
+
this.meetingMuted = false;
|
146
|
+
} else {
|
147
|
+
console.log('You cannot unmute yourself');
|
148
|
+
}
|
149
|
+
},
|
150
|
+
parepareAttendeeStatus() {
|
151
|
+
this.presentAttendeeMap = {};
|
152
|
+
const callback = (presentAttendeeId, present) => {
|
153
|
+
if (present) {
|
154
|
+
axios
|
155
|
+
.get(`/rooms/${this.room_id}/meetings/${this.meeting_id}/attendees/${presentAttendeeId}`)
|
156
|
+
.then(response => {
|
157
|
+
this.presentAttendeeMap[presentAttendeeId] = response.data;
|
158
|
+
this.updateAttendeeStatus(this.presentAttendeeMap);
|
159
|
+
})
|
160
|
+
.catch(error => {
|
161
|
+
console.log(error);
|
162
|
+
});
|
163
|
+
} else {
|
164
|
+
delete this.presentAttendeeMap[presentAttendeeId]
|
165
|
+
this.updateAttendeeStatus(this.presentAttendeeMap);
|
166
|
+
}
|
167
|
+
};
|
168
|
+
this.meetingSession.audioVideo.realtimeSubscribeToAttendeeIdPresence(callback);
|
169
|
+
},
|
170
|
+
updateAttendeeStatus(presentAttendeeMap) {
|
171
|
+
this.presentAttendees = Object.values(presentAttendeeMap).map(attendee => this.showApplicationUserName(attendee));
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
</script>
|
176
|
+
|
177
|
+
<style scoped>
|
178
|
+
</style>
|
@@ -0,0 +1,53 @@
|
|
1
|
+
<template>
|
2
|
+
<div>
|
3
|
+
<p id="notice">{{ notice }}</p>
|
4
|
+
|
5
|
+
<h1>Rooms</h1>
|
6
|
+
|
7
|
+
<table>
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th>Name</th>
|
11
|
+
<th colspan="3"></th>
|
12
|
+
</tr>
|
13
|
+
</thead>
|
14
|
+
|
15
|
+
<tbody>
|
16
|
+
<tr v-for="room in rooms" :key="`${room.id}`">
|
17
|
+
<td>{{ room.name }}</td>
|
18
|
+
<td><router-link v-bind:to="{ name: 'Room', params: { room_id: room.id } }">Show</router-link></td>
|
19
|
+
<td><a v-bind:href="`/rooms/${room.id}/edit`">(Edit)</a></td>
|
20
|
+
<td><a v-bind:href="`/rooms/${room.id}`" data-method="delete" data-confirm="Are you sure?" rel="nofollow">(Destroy)</a></td>
|
21
|
+
</tr>
|
22
|
+
</tbody>
|
23
|
+
</table>
|
24
|
+
|
25
|
+
<br>
|
26
|
+
|
27
|
+
<a href="/rooms/new">(New Room)</a>
|
28
|
+
</div>
|
29
|
+
</template>
|
30
|
+
|
31
|
+
<script>
|
32
|
+
import axios from 'axios'
|
33
|
+
|
34
|
+
export default {
|
35
|
+
name: 'Rooms',
|
36
|
+
data () {
|
37
|
+
return {
|
38
|
+
rooms: [],
|
39
|
+
notice: null
|
40
|
+
}
|
41
|
+
},
|
42
|
+
mounted () {
|
43
|
+
axios
|
44
|
+
.get('/rooms')
|
45
|
+
.then(response => {
|
46
|
+
this.rooms = response.data;
|
47
|
+
})
|
48
|
+
}
|
49
|
+
}
|
50
|
+
</script>
|
51
|
+
|
52
|
+
<style scoped>
|
53
|
+
</style>
|
@@ -0,0 +1,91 @@
|
|
1
|
+
<template>
|
2
|
+
<div v-if="room">
|
3
|
+
<p id="notice">{{ notice }}</p>
|
4
|
+
|
5
|
+
<p>
|
6
|
+
<strong>Name:</strong>
|
7
|
+
{{ room.name }}
|
8
|
+
</p>
|
9
|
+
|
10
|
+
<p>
|
11
|
+
<strong>Private Meeting:</strong>
|
12
|
+
<p><router-link v-bind:to="{ name: 'Meetings', params: { room_id: room.id } }">Show Meetings</router-link></p>
|
13
|
+
<p><a href="#" v-on:click="create_meeting(room)" data-remote="true">Create Meeting</a></p>
|
14
|
+
</p>
|
15
|
+
|
16
|
+
<p>
|
17
|
+
<strong>Members:</strong>
|
18
|
+
<div>
|
19
|
+
<table>
|
20
|
+
<tbody>
|
21
|
+
<tr v-for="member in room.members" :key="`${member.name}`">
|
22
|
+
<td>{{ member.name }}</td>
|
23
|
+
</tr>
|
24
|
+
</tbody>
|
25
|
+
</table>
|
26
|
+
</div>
|
27
|
+
</p>
|
28
|
+
|
29
|
+
<p>
|
30
|
+
<strong>Manage members:</strong>
|
31
|
+
<a v-bind:href="`/rooms/${room.id}`">(Show)</a>
|
32
|
+
</p>
|
33
|
+
|
34
|
+
<br>
|
35
|
+
|
36
|
+
<a v-bind:href="`/rooms/${room.id}/edit`">(Edit)</a>
|
37
|
+
<router-link v-bind:to="{ name: 'Rooms' }">Back</router-link>
|
38
|
+
</div>
|
39
|
+
</template>
|
40
|
+
|
41
|
+
<script>
|
42
|
+
import axios from 'axios'
|
43
|
+
|
44
|
+
export default {
|
45
|
+
name: 'Room',
|
46
|
+
props: {
|
47
|
+
room_id: {
|
48
|
+
required: true
|
49
|
+
},
|
50
|
+
message: String
|
51
|
+
},
|
52
|
+
data () {
|
53
|
+
return {
|
54
|
+
room: null,
|
55
|
+
notice: this.message
|
56
|
+
}
|
57
|
+
},
|
58
|
+
mounted () {
|
59
|
+
axios
|
60
|
+
.get(`/rooms/${this.room_id}`)
|
61
|
+
.then(response => {
|
62
|
+
this.room = response.data;
|
63
|
+
})
|
64
|
+
.catch(error => {
|
65
|
+
this.notice = error;
|
66
|
+
})
|
67
|
+
},
|
68
|
+
methods: {
|
69
|
+
create_meeting (room_id) {
|
70
|
+
axios
|
71
|
+
.post(`/rooms/${this.room_id}/meetings`)
|
72
|
+
.then(response => {
|
73
|
+
if (response.status == 201) {
|
74
|
+
let meeting_id = response.data.Meeting.MeetingId;
|
75
|
+
this.$router.push({ name: 'Meeting', params: { room_id: this.room_id, meeting_id: meeting_id, message: `Meeting <${meeting_id}> was successfully created.` } });
|
76
|
+
}
|
77
|
+
})
|
78
|
+
.catch (error => {
|
79
|
+
if (error.response.status == 403) {
|
80
|
+
this.notice = error.response.data.notice;
|
81
|
+
} else {
|
82
|
+
this.notice = error;
|
83
|
+
}
|
84
|
+
})
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
</script>
|
89
|
+
|
90
|
+
<style scoped>
|
91
|
+
</style>
|