@windward/integrations 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/components/Content/Blocks/ExternalIntegration/LtiConsumer.vue +15 -0
  2. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumer.vue +3 -7
  3. package/components/ExternalIntegration/Driver/Lti1p1/ManageConsumers.vue +10 -14
  4. package/components/ExternalIntegration/Driver/Lti1p1/ManageProvider.vue +28 -21
  5. package/components/ExternalIntegration/Driver/Lti1p1/ManageProviders.vue +25 -11
  6. package/components/ExternalIntegration/Driver/Lti1p3/ManageProvider.vue +445 -0
  7. package/components/ExternalIntegration/Driver/Lti1p3/ManageProviders.vue +259 -0
  8. package/components/ExternalIntegration/Driver/ManageLti1p1.vue +2 -2
  9. package/components/ExternalIntegration/Driver/ManageLti1p3.vue +45 -0
  10. package/components/ExternalIntegration/ProviderTargetPicker.vue +21 -37
  11. package/components/Integration/Driver/ManageAtutor.vue +15 -0
  12. package/components/Integration/JobLog.vue +98 -0
  13. package/components/Integration/JobTable.vue +15 -1
  14. package/i18n/en-US/components/content/blocks/external_integration/lti_consumer.ts +2 -0
  15. package/i18n/en-US/components/external_integration/driver/lti1p1.ts +0 -21
  16. package/i18n/en-US/components/external_integration/driver/lti1p3.ts +13 -0
  17. package/i18n/en-US/components/external_integration/index.ts +26 -1
  18. package/i18n/en-US/components/integration/driver.ts +1 -0
  19. package/i18n/en-US/components/integration/job.ts +3 -0
  20. package/i18n/en-US/pages/login/lti.ts +1 -1
  21. package/models/ExternalIntegration/{Lti1p1Provider.ts → LtiProvider.ts} +2 -2
  22. package/package.json +1 -1
  23. package/pages/admin/importCourse.vue +1 -1
  24. package/pages/admin/vendors.vue +3 -2
  25. package/pages/course/externalIntegration/index.vue +4 -3
  26. package/plugin.js +48 -1
  27. package/test/Components/ExternalIntegration/Lti1p3/ManageProvider.spec.js +19 -0
  28. package/test/Components/ExternalIntegration/Lti1p3/ManageProviders.spec.js +19 -0
  29. package/test/Components/ExternalIntegration/ManageLti1p3.spec.js +19 -0
  30. package/test/Components/ExternalIntegration/ProviderTargetPicker.spec.js +1 -1
  31. package/test/Components/Integration/JobLog.spec.js +22 -0
  32. package/test/Components/Integration/JobTable.spec.js +23 -0
  33. package/test/__mocks__/componentsMock.js +12 -0
  34. package/test/mocks.js +12 -0
@@ -0,0 +1,445 @@
1
+ <template>
2
+ <div>
3
+ <div v-if="!render" class="integration-loading">
4
+ <v-progress-circular size="128" indeterminate />
5
+ </div>
6
+ <div v-if="render">
7
+ <v-form ref="form" v-model="formValid" @submit.prevent>
8
+ <v-row justify="center" align="center">
9
+ <v-col cols="12">
10
+ <ProviderTargetPicker
11
+ v-model="provider"
12
+ ></ProviderTargetPicker>
13
+
14
+ <v-text-field
15
+ id="target-url"
16
+ v-model="provider.target"
17
+ disabled
18
+ :label="
19
+ $t(
20
+ 'windward.integrations.components.external_integration.target_url'
21
+ )
22
+ "
23
+ :hint="
24
+ $t(
25
+ 'windward.integrations.components.external_integration.target_url'
26
+ )
27
+ "
28
+ :rules="validation.existsRules"
29
+ ></v-text-field>
30
+
31
+ <v-switch
32
+ v-model="provider.enabled"
33
+ :label="$t('shared.forms.enabled')"
34
+ />
35
+
36
+ <v-switch
37
+ v-model="provider.grade_sync"
38
+ :label="
39
+ $t(
40
+ 'windward.integrations.components.external_integration.send_grades'
41
+ )
42
+ "
43
+ />
44
+ <v-text-field
45
+ id="lti-keyset_url"
46
+ v-model="
47
+ provider.metadata.platform_public_keyset_url
48
+ "
49
+ :label="
50
+ $t(
51
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_public_keyset_url'
52
+ )
53
+ "
54
+ :hint="
55
+ $t(
56
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_public_keyset_url'
57
+ )
58
+ "
59
+ :rules="validation.existsRules"
60
+ ></v-text-field>
61
+
62
+ <v-text-field
63
+ id="lti-oidc-auth-endpoint"
64
+ v-model="
65
+ provider.metadata.platform_oidc_auth_endpoint
66
+ "
67
+ :placeholder="
68
+ $t(
69
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oidc_auth_endpoint'
70
+ )
71
+ "
72
+ :label="
73
+ $t(
74
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oidc_auth_endpoint'
75
+ )
76
+ "
77
+ :hint="
78
+ $t(
79
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oidc_auth_endpoint'
80
+ )
81
+ "
82
+ :rules="validation.existsRules"
83
+ >
84
+ </v-text-field>
85
+ <v-text-field
86
+ id="lti-client-id"
87
+ v-model="provider.metadata.platform_client_id"
88
+ :placeholder="
89
+ $t(
90
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_client_id'
91
+ )
92
+ "
93
+ :label="
94
+ $t(
95
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_client_id'
96
+ )
97
+ "
98
+ :hint="
99
+ $t(
100
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_client_id'
101
+ )
102
+ "
103
+ >
104
+ </v-text-field>
105
+ <v-text-field
106
+ id="lti-deployment-id"
107
+ v-model="provider.metadata.platform_deployment_id"
108
+ :placeholder="
109
+ $t(
110
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_deployment_id'
111
+ )
112
+ "
113
+ :label="
114
+ $t(
115
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_deployment_id'
116
+ )
117
+ "
118
+ :hint="
119
+ $t(
120
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_deployment_id'
121
+ )
122
+ "
123
+ >
124
+ </v-text-field>
125
+ </v-col>
126
+ </v-row>
127
+ <v-row>
128
+ <v-col cols="12">
129
+ <v-expansion-panels v-model="rolePanel">
130
+ <v-expansion-panel>
131
+ <v-expansion-panel-header>
132
+ {{
133
+ $t(
134
+ 'windward.integrations.components.external_integration.role_map_panel'
135
+ )
136
+ }}
137
+ </v-expansion-panel-header>
138
+ <v-expansion-panel-content>
139
+ <p>
140
+ <strong>
141
+ {{
142
+ $t(
143
+ 'windward.integrations.components.external_integration.role_map_instructions'
144
+ )
145
+ }}
146
+ </strong>
147
+ </p>
148
+ <p>
149
+ {{
150
+ $t(
151
+ 'windward.integrations.components.external_integration.role_map_warning'
152
+ )
153
+ }}
154
+ </p>
155
+ <v-simple-table>
156
+ <template #default>
157
+ <thead>
158
+ <tr>
159
+ <th>
160
+ {{
161
+ $t(
162
+ 'windward.integrations.components.external_integration.role_in_host'
163
+ )
164
+ }}
165
+ </th>
166
+ <th>
167
+ {{
168
+ $t(
169
+ 'windward.integrations.components.external_integration.role_in_local'
170
+ )
171
+ }}
172
+ </th>
173
+ </tr>
174
+ </thead>
175
+ <tbody>
176
+ <tr
177
+ v-for="(
178
+ id, externalName
179
+ ) in provider.role_metadata"
180
+ :key="externalName"
181
+ >
182
+ <td>
183
+ {{
184
+ uppercase(
185
+ externalName
186
+ )
187
+ }}
188
+ </td>
189
+ <td>
190
+ <v-select
191
+ v-model="
192
+ provider
193
+ .role_metadata[
194
+ externalName
195
+ ]
196
+ "
197
+ :items="roles"
198
+ item-value="id"
199
+ item-text="name"
200
+ :label="
201
+ $t(
202
+ 'windward.integrations.components.external_integration.map_to_role'
203
+ )
204
+ "
205
+ ></v-select>
206
+ </td>
207
+ <td>
208
+ <v-btn
209
+ icon
210
+ @click="
211
+ deleteMapItem(
212
+ externalName
213
+ )
214
+ "
215
+ >
216
+ <v-icon>
217
+ mdi-delete
218
+ </v-icon>
219
+ <span
220
+ class="sr-only"
221
+ >
222
+ {{
223
+ $t(
224
+ 'windward.integrations.components.external_integration.delete_role_map_item'
225
+ )
226
+ }}
227
+ </span>
228
+ </v-btn>
229
+ </td>
230
+ </tr>
231
+ <tr>
232
+ <td>
233
+ <v-text-field
234
+ v-model="
235
+ newMap.name
236
+ "
237
+ :label="
238
+ $t(
239
+ 'windward.integrations.components.external_integration.remote_role'
240
+ )
241
+ "
242
+ ></v-text-field>
243
+ </td>
244
+ <td>
245
+ <v-select
246
+ v-model="newMap.id"
247
+ :items="roles"
248
+ :label="
249
+ $t(
250
+ 'windward.integrations.components.external_integration.map_to_role'
251
+ )
252
+ "
253
+ item-value="id"
254
+ item-text="name"
255
+ ></v-select>
256
+ </td>
257
+ <td>
258
+ <v-btn
259
+ icon
260
+ :disabled="
261
+ !newMap.id ||
262
+ !newMap.name
263
+ "
264
+ @click="addMapItem"
265
+ >
266
+ <v-icon>
267
+ mdi-plus
268
+ </v-icon>
269
+ <span
270
+ class="sr-only"
271
+ >
272
+ {{
273
+ $t(
274
+ 'windward.integrations.components.external_integration.add_role_map_item'
275
+ )
276
+ }}
277
+ </span>
278
+ </v-btn>
279
+ </td>
280
+ </tr>
281
+ </tbody>
282
+ </template>
283
+ </v-simple-table>
284
+ </v-expansion-panel-content>
285
+ </v-expansion-panel>
286
+ </v-expansion-panels>
287
+ </v-col>
288
+ </v-row>
289
+ </v-form>
290
+ </div>
291
+ </div>
292
+ </template>
293
+
294
+ <script>
295
+ import _ from 'lodash'
296
+ import { mapGetters } from 'vuex'
297
+ import ProviderTargetPicker from '../../ProviderTargetPicker.vue'
298
+ import LtiProvider from '../../../../models/ExternalIntegration/LtiProvider'
299
+
300
+ import FormVue from '~/components/Form.vue'
301
+ import Role from '~/models/Role'
302
+ import Organization from '~/models/Organization'
303
+ import Course from '~/models/Course'
304
+
305
+ export default {
306
+ name: 'ManageLti1p3ProviderDriver',
307
+ components: { ProviderTargetPicker },
308
+ extends: FormVue,
309
+ props: {
310
+ value: {
311
+ type: [LtiProvider, null],
312
+ required: false,
313
+ default: null,
314
+ },
315
+ },
316
+ emits: ['update:provider'],
317
+ data() {
318
+ return {
319
+ render: false,
320
+ provider: {
321
+ role_metadata: {},
322
+ metadata: {},
323
+ version: '1.3',
324
+ },
325
+ rolePanel: false,
326
+ roles: [],
327
+ newMap: {
328
+ name: null,
329
+ id: null,
330
+ },
331
+ }
332
+ },
333
+ async fetch() {
334
+ // Get available roles but filter out default high level roles since they'll be ignore anyways from the api
335
+ this.roles = await Role.whereIn('name,ne', [
336
+ 'admin',
337
+ 'editor',
338
+ 'instructor',
339
+ 'student',
340
+ ]).all()
341
+ },
342
+ computed: {
343
+ ...mapGetters({
344
+ organization: 'organization/get',
345
+ course: 'course/get',
346
+ contentTree: 'content/getTree',
347
+ }),
348
+ },
349
+ created() {
350
+ if (_.isEmpty(this.value)) {
351
+ this.provider = new LtiProvider({
352
+ role_metadata: {},
353
+ metadata: {},
354
+ version: '1.3',
355
+ })
356
+ } else {
357
+ this.provider = _.cloneDeep(this.value)
358
+ }
359
+ },
360
+ mounted() {
361
+ if (
362
+ !this.$PermissionService.userHasAccessTo(
363
+ 'plugin.windward.integrations.course.externalIntegration',
364
+ 'writable'
365
+ )
366
+ ) {
367
+ // Display an angry error that they can't view this driver
368
+ this.$dialog.error(this.$t('shared.error.description_401'), {
369
+ duration: null,
370
+ action: {
371
+ text: this.$t('shared.forms.close'),
372
+ onClick: (_e, toastObject) => {
373
+ toastObject.goAway(0)
374
+ },
375
+ },
376
+ })
377
+ // eslint-disable-next-line no-console
378
+ console.error('You do not have access to this provider!')
379
+
380
+ // Return so we don't even attempt loading
381
+ return false
382
+ }
383
+
384
+ this.render = true
385
+ },
386
+ methods: {
387
+ uppercase(value) {
388
+ return _.startCase(value)
389
+ },
390
+ deleteMapItem(key) {
391
+ this.$delete(this.provider.role_metadata, key)
392
+ },
393
+ addMapItem() {
394
+ this.provider.role_metadata[this.newMap.name] = this.newMap.id
395
+ this.newMap.name = null
396
+ this.newMap.id = null
397
+ },
398
+ async save() {
399
+ let provider = new LtiProvider(this.provider).for(
400
+ new Organization({ id: this.organization.id }),
401
+ new Course({ id: this.course.id })
402
+ )
403
+
404
+ try {
405
+ provider = await provider.save()
406
+ this.provider = provider
407
+
408
+ // Clone and delete the metadata since we don't need to share that around
409
+ // Also include the vendor going back for easier mapping
410
+ const providerEvent = _.cloneDeep(provider)
411
+
412
+ this.$dialog.success(this.$t('shared.forms.saved'))
413
+ this.$emit('update:provider', providerEvent)
414
+ this.$emit('input', provider)
415
+ } catch (e) {
416
+ this.$dialog.error(
417
+ this.$t('windward.integrations.shared.error.save_failed')
418
+ )
419
+ }
420
+
421
+ // Create a new provider to clear the form if the original value is empty aka new
422
+ if (_.isEmpty(this.value)) {
423
+ this.provider = new LtiProvider({
424
+ role_metadata: {},
425
+ metadata: {},
426
+ version: '1.3',
427
+ })
428
+ }
429
+ },
430
+ async onSave() {
431
+ this.$refs.form.validate()
432
+ if (this.formValid) {
433
+ await this.save()
434
+ }
435
+ },
436
+
437
+ async onSaveAndNew() {
438
+ this.$refs.form.validate()
439
+ if (this.formValid) {
440
+ await this.save()
441
+ }
442
+ },
443
+ },
444
+ }
445
+ </script>