@windward/integrations 0.0.11 → 0.1.0

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.
@@ -0,0 +1,229 @@
1
+ <template>
2
+ <div>
3
+ <Dialog
4
+ color="primary"
5
+ action-save
6
+ action-save-new
7
+ @click:save="onSaved"
8
+ >
9
+ <template #title>{{
10
+ $t(
11
+ 'windward.integrations.components.external_integration.driver.lti1p1.new'
12
+ )
13
+ }}</template>
14
+ <template #trigger>{{
15
+ $t(
16
+ 'windward.integrations.components.external_integration.driver.lti1p1.new'
17
+ )
18
+ }}</template>
19
+ <template #form="{ on, attrs }"
20
+ ><ManageConsumer v-bind="attrs" v-on="on"></ManageConsumer
21
+ ></template>
22
+ </Dialog>
23
+
24
+ <v-data-table
25
+ :headers="headers"
26
+ :items="consumers"
27
+ :items-per-page="10"
28
+ class="elevation-1"
29
+ >
30
+ <template #[`item.description`]="{ item }">
31
+ {{ item.description.replace(/(<([^>]+)>)/gi, '').trim() }}
32
+ </template>
33
+
34
+ <template #[`item.enabled`]="{ item }">
35
+ <v-icon :color="item.enabled ? 'success' : 'error'"
36
+ >{{ item.enabled ? 'mdi-check' : 'mdi-close' }}
37
+ </v-icon>
38
+ <span v-if="!item.enabled" class="sr-only">{{
39
+ $t('shared.forms.enabled')
40
+ }}</span>
41
+ </template>
42
+
43
+ <template #[`item.created_at`]="{ item }">
44
+ {{ $d(new Date(item.created_at), 'long') }}
45
+ </template>
46
+ <template #[`item.actions`]="{ index, item }">
47
+ <Dialog color="primary">
48
+ <template #title>{{
49
+ $t(
50
+ 'windward.integrations.components.external_integration.driver.lti1p3.view'
51
+ )
52
+ }}</template>
53
+ <template #trigger>
54
+ <v-icon small>mdi-eye-outline</v-icon>
55
+ <span class="sr-only">{{
56
+ $t(
57
+ 'windward.integrations.components.external_integration.driver.lti1p3.view'
58
+ )
59
+ }}</span>
60
+ </template>
61
+ <template #form="{ on, attrs }"
62
+ ><ViewConsumer
63
+ v-model="consumers[index]"
64
+ v-bind="attrs"
65
+ v-on="on"
66
+ ></ViewConsumer
67
+ ></template>
68
+ </Dialog>
69
+ <Dialog color="primary" action-save @click:save="onSaved">
70
+ <template #title>{{
71
+ $t(
72
+ 'windward.integrations.components.external_integration.driver.lti1p3.edit'
73
+ )
74
+ }}</template>
75
+ <template #trigger>
76
+ <v-icon small>mdi-pencil</v-icon>
77
+ <span class="sr-only">{{
78
+ $t(
79
+ 'windward.integrations.components.external_integration.driver.lti1p3.edit'
80
+ )
81
+ }}</span>
82
+ </template>
83
+ <template #form="{ on, attrs }"
84
+ ><ManageConsumer
85
+ v-model="consumers[index]"
86
+ v-bind="attrs"
87
+ v-on="on"
88
+ ></ManageConsumer
89
+ ></template>
90
+ </Dialog>
91
+
92
+ <v-btn icon>
93
+ <v-icon @click="onConfirmDelete(item)"> mdi-delete </v-icon>
94
+ <span class="sr-only">{{ $t('shared.forms.delete') }}</span>
95
+ </v-btn>
96
+ </template>
97
+ </v-data-table>
98
+ </div>
99
+ </template>
100
+
101
+ <script>
102
+ import _ from 'lodash'
103
+ import { mapGetters } from 'vuex'
104
+ import LtiConsumer from '../../../../models/ExternalIntegration/LtiConsumer'
105
+ import ManageConsumer from './ManageConsumer.vue'
106
+ import ViewConsumer from './ViewConsumer.vue'
107
+ import Course from '~/models/Course'
108
+ import Organization from '~/models/Organization'
109
+ import Dialog from '~/components/Dialog.vue'
110
+
111
+ export default {
112
+ name: 'ManageLti1p1ConsumersDriver',
113
+ components: { Dialog, ManageConsumer, ViewConsumer },
114
+ data() {
115
+ return {
116
+ consumers: [],
117
+ headers: [
118
+ {
119
+ text: this.$t(
120
+ 'windward.integrations.components.external_integration.target_url'
121
+ ),
122
+ value: 'target',
123
+ },
124
+ {
125
+ text: this.$t('shared.forms.name'),
126
+ value: 'name',
127
+ },
128
+ {
129
+ text: this.$t('shared.forms.description'),
130
+ value: 'description',
131
+ },
132
+ {
133
+ text: this.$t('shared.forms.enabled'),
134
+ value: 'enabled',
135
+ },
136
+ { text: this.$t('shared.forms.created'), value: 'created_at' },
137
+ {
138
+ text: this.$t('shared.forms.actions'),
139
+ value: 'actions',
140
+ sortable: false,
141
+ },
142
+ ],
143
+ }
144
+ },
145
+
146
+ async fetch() {
147
+ if (
148
+ !this.$PermissionService.userHasAccessTo(
149
+ 'plugin.windward.integrations.course.externalIntegration',
150
+ 'readable'
151
+ ) ||
152
+ _.isEmpty(this.organization.id) ||
153
+ _.isEmpty(this.course.id)
154
+ ) {
155
+ // Display an angry error that they can't view this driver
156
+ this.$dialog.error(this.$t('shared.error.description_401'), {
157
+ duration: null,
158
+ action: {
159
+ text: this.$t('shared.forms.close'),
160
+ onClick: (_e, toastObject) => {
161
+ toastObject.goAway(0)
162
+ },
163
+ },
164
+ })
165
+ if (_.isEmpty(this.organization.id) || _.isEmpty(this.course.id)) {
166
+ // eslint-disable-next-line no-console
167
+ console.error(
168
+ 'Cannot load external integrations because organization or course is not set!'
169
+ )
170
+ } else {
171
+ // eslint-disable-next-line no-console
172
+ console.error(
173
+ 'You do not have access to this external integration!'
174
+ )
175
+ }
176
+
177
+ // Return so we don't even attempt loading
178
+ return false
179
+ }
180
+
181
+ await this.loadConsumers()
182
+ },
183
+ computed: {
184
+ ...mapGetters({
185
+ organization: 'organization/get',
186
+ course: 'course/get',
187
+ }),
188
+ },
189
+ methods: {
190
+ onSaved() {
191
+ this.loadConsumers()
192
+ },
193
+ async loadConsumers() {
194
+ this.consumers = await new LtiConsumer()
195
+ .for(
196
+ new Organization({ id: this.organization.id }),
197
+ new Course({ id: this.course.id })
198
+ )
199
+ .where('version', '1.3')
200
+ .get()
201
+ },
202
+ onConfirmDelete(consumer) {
203
+ this.$dialog.show(this.$t('shared.forms.confirm_delete_text'), {
204
+ icon: 'mdi-help',
205
+ duration: null,
206
+ action: [
207
+ {
208
+ text: this.$t('shared.forms.cancel'),
209
+ onClick: (_e, toastObject) => {
210
+ toastObject.goAway(0)
211
+ },
212
+ },
213
+ {
214
+ text: this.$t('shared.forms.confirm'),
215
+ // router navigation
216
+ onClick: (_e, toastObject) => {
217
+ this.deleteConsumer(consumer)
218
+ toastObject.goAway(0)
219
+ },
220
+ },
221
+ ],
222
+ })
223
+ },
224
+ deleteConsumer(consumer) {
225
+ consumer.delete()
226
+ },
227
+ },
228
+ }
229
+ </script>
@@ -30,9 +30,9 @@
30
30
 
31
31
  <v-switch
32
32
  v-model="provider.enabled"
33
- :label="$t('shared.forms.enabled')"
33
+ :label="providerEnableLabel"
34
+ :disabled="!canBeEnabled"
34
35
  />
35
-
36
36
  <v-switch
37
37
  v-model="provider.grade_sync"
38
38
  :label="
@@ -41,6 +41,36 @@
41
41
  )
42
42
  "
43
43
  />
44
+
45
+ <v-text-field
46
+ id="lti-pid"
47
+ v-model="provider.metadata.platform_name"
48
+ :label="
49
+ $t(
50
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_name'
51
+ )
52
+ "
53
+ :hint="
54
+ $t(
55
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_name'
56
+ )
57
+ "
58
+ ></v-text-field>
59
+ <v-text-field
60
+ id="lti-pid"
61
+ v-model="provider.metadata.platform_id"
62
+ :label="
63
+ $t(
64
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_id'
65
+ )
66
+ "
67
+ :hint="
68
+ $t(
69
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_id'
70
+ )
71
+ "
72
+ ></v-text-field>
73
+
44
74
  <v-text-field
45
75
  id="lti-keyset_url"
46
76
  v-model="
@@ -56,7 +86,6 @@
56
86
  'windward.integrations.components.external_integration.driver.lti1p3.platform_public_keyset_url'
57
87
  )
58
88
  "
59
- :rules="validation.existsRules"
60
89
  ></v-text-field>
61
90
 
62
91
  <v-text-field
@@ -79,25 +108,55 @@
79
108
  'windward.integrations.components.external_integration.driver.lti1p3.platform_oidc_auth_endpoint'
80
109
  )
81
110
  "
82
- :rules="validation.existsRules"
83
111
  >
84
112
  </v-text-field>
113
+ <v-text-field
114
+ id="lti-oauth2-url"
115
+ v-model="
116
+ provider.metadata
117
+ .platform_oauth2_access_token_url
118
+ "
119
+ :label="
120
+ $t(
121
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oauth2_access_token_url'
122
+ )
123
+ "
124
+ :hint="
125
+ $t(
126
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oauth2_access_token_url'
127
+ )
128
+ "
129
+ ></v-text-field>
130
+ <v-text-field
131
+ id="lti-oauth2-aud"
132
+ v-model="provider.metadata.platform_oauth2_audience"
133
+ :label="
134
+ $t(
135
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oauth2_audience'
136
+ )
137
+ "
138
+ :hint="
139
+ $t(
140
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oauth2_audience'
141
+ )
142
+ "
143
+ ></v-text-field>
85
144
  <v-text-field
86
145
  id="lti-client-id"
87
- v-model="provider.metadata.platform_client_id"
146
+ v-model="provider.metadata.tool_client_id"
88
147
  :placeholder="
89
148
  $t(
90
- 'windward.integrations.components.external_integration.driver.lti1p3.platform_client_id'
149
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_client_id'
91
150
  )
92
151
  "
93
152
  :label="
94
153
  $t(
95
- 'windward.integrations.components.external_integration.driver.lti1p3.platform_client_id'
154
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_client_id'
96
155
  )
97
156
  "
98
157
  :hint="
99
158
  $t(
100
- 'windward.integrations.components.external_integration.driver.lti1p3.platform_client_id'
159
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_client_id'
101
160
  )
102
161
  "
103
162
  >
@@ -321,6 +380,7 @@ export default {
321
380
  role_metadata: {},
322
381
  metadata: {},
323
382
  version: '1.3',
383
+ enabled: false,
324
384
  },
325
385
  rolePanel: false,
326
386
  roles: [],
@@ -345,6 +405,29 @@ export default {
345
405
  course: 'course/get',
346
406
  contentTree: 'content/getTree',
347
407
  }),
408
+ canBeEnabled() {
409
+ if (
410
+ this.provider.metadata.platform_public_keyset_url &&
411
+ this.provider.metadata.platform_oidc_auth_endpoint
412
+ ) {
413
+ return true
414
+ }
415
+ return false
416
+ },
417
+ providerEnableLabel() {
418
+ if (this.canBeEnabled) {
419
+ return this.$t('shared.forms.enabled')
420
+ } else {
421
+ return (
422
+ this.$t('shared.forms.disabled') +
423
+ ' (' +
424
+ this.$t(
425
+ 'windward.integrations.components.external_integration.driver.lti1p3.enable_button_feedback'
426
+ ) +
427
+ ')'
428
+ )
429
+ }
430
+ },
348
431
  },
349
432
  created() {
350
433
  if (_.isEmpty(this.value)) {
@@ -0,0 +1,224 @@
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 v-model="formValid" @submit.prevent>
8
+ <v-row justify="center" align="center" class="mt-5">
9
+ <v-col cols="12">
10
+ <SecretField
11
+ v-model="consumer.metadata.platform_id"
12
+ :hidden="false"
13
+ :placeholder="
14
+ $t(
15
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_id'
16
+ )
17
+ "
18
+ :label="
19
+ $t(
20
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_id'
21
+ )
22
+ "
23
+ ></SecretField>
24
+ <SecretField
25
+ v-model="consumer.metadata.client_id"
26
+ :hidden="false"
27
+ :placeholder="
28
+ $t(
29
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_client_id'
30
+ )
31
+ "
32
+ :label="
33
+ $t(
34
+ 'windward.integrations.components.external_integration.driver.lti1p3.tool_client_id'
35
+ )
36
+ "
37
+ ></SecretField>
38
+ <SecretField
39
+ v-model="consumer.metadata.deployment_id"
40
+ :hidden="false"
41
+ :placeholder="
42
+ $t(
43
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_deployment_id'
44
+ )
45
+ "
46
+ :label="
47
+ $t(
48
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_deployment_id'
49
+ )
50
+ "
51
+ ></SecretField>
52
+ <SecretField
53
+ v-model="
54
+ consumer.metadata.platform_oidc_auth_endpoint
55
+ "
56
+ :hidden="false"
57
+ :placeholder="
58
+ $t(
59
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oidc_auth_endpoint'
60
+ )
61
+ "
62
+ :label="
63
+ $t(
64
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oidc_auth_endpoint'
65
+ )
66
+ "
67
+ ></SecretField>
68
+ <SecretField
69
+ v-model="
70
+ consumer.metadata.platform_public_keyset_url
71
+ "
72
+ :hidden="false"
73
+ :placeholder="
74
+ $t(
75
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_public_keyset_url'
76
+ )
77
+ "
78
+ :label="
79
+ $t(
80
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_public_keyset_url'
81
+ )
82
+ "
83
+ ></SecretField>
84
+ <SecretField
85
+ v-model="
86
+ consumer.metadata
87
+ .platform_oauth2_access_token_url
88
+ "
89
+ :hidden="false"
90
+ :placeholder="
91
+ $t(
92
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oauth2_access_token_url'
93
+ )
94
+ "
95
+ :label="
96
+ $t(
97
+ 'windward.integrations.components.external_integration.driver.lti1p3.platform_oauth2_access_token_url'
98
+ )
99
+ "
100
+ ></SecretField>
101
+ </v-col>
102
+ </v-row>
103
+ </v-form>
104
+ </div>
105
+ </div>
106
+ </template>
107
+
108
+ <script>
109
+ import _ from 'lodash'
110
+ import { mapGetters } from 'vuex'
111
+ import LtiConsumer from '../../../../models/ExternalIntegration/LtiConsumer'
112
+ import SecretField from '../../../SecretField.vue'
113
+ import Organization from '~/models/Organization'
114
+ import Course from '~/models/Course'
115
+ import FormVue from '~/components/Form'
116
+ export default {
117
+ name: 'ViewLti1p3Consumer',
118
+ components: { SecretField },
119
+ extends: FormVue,
120
+ props: {
121
+ value: {
122
+ type: [LtiConsumer, null],
123
+ required: false,
124
+ default: null,
125
+ },
126
+ },
127
+ emits: ['view:consumer'],
128
+ meta: {
129
+ privilege: {
130
+ '': {
131
+ writable: true,
132
+ },
133
+ },
134
+ },
135
+ data() {
136
+ return {
137
+ render: false,
138
+ consumer: {
139
+ version: '1.3',
140
+ metadata: {
141
+ custom: [],
142
+ security_level: '',
143
+ security: [],
144
+ },
145
+ },
146
+ }
147
+ },
148
+ computed: {
149
+ ...mapGetters({
150
+ organization: 'organization/get',
151
+ course: 'course/get',
152
+ }),
153
+ },
154
+ created() {
155
+ if (_.isEmpty(this.value)) {
156
+ this.consumer = new LtiConsumer(this.consumer)
157
+ } else {
158
+ this.consumer = new LtiConsumer(_.cloneDeep(this.value))
159
+ }
160
+ },
161
+ mounted() {
162
+ if (
163
+ !this.$PermissionService.userHasAccessTo(
164
+ 'plugin.windward.integrations.course.externalIntegration',
165
+ 'writable'
166
+ )
167
+ ) {
168
+ // Display an angry error that they can't view this driver
169
+ this.$dialog.error(this.$t('shared.error.description_401'), {
170
+ duration: null,
171
+ action: {
172
+ text: this.$t('shared.forms.close'),
173
+ onClick: (_e, toastObject) => {
174
+ toastObject.goAway(0)
175
+ },
176
+ },
177
+ })
178
+
179
+ // eslint-disable-next-line no-console
180
+ console.error('You do not have access to this consumer!')
181
+
182
+ // Return so we don't even attempt loading
183
+ return false
184
+ }
185
+
186
+ this.render = true
187
+ },
188
+ methods: {
189
+ addCustomParameter() {
190
+ this.consumer.metadata.custom.push({ key: '', value: '' })
191
+ },
192
+ deleteCustomParameter(index) {
193
+ this.consumer.metadata.custom.splice(index, 1)
194
+ },
195
+ async save() {
196
+ let consumer = new LtiConsumer(this.consumer).for(
197
+ new Organization({ id: this.organization.id }),
198
+ new Course({ id: this.course.id })
199
+ )
200
+
201
+ try {
202
+ consumer = await consumer.save()
203
+ this.consumer = consumer
204
+
205
+ // Clone and delete the metadata since we don't need to share that around
206
+ // Also include the vendor going back for easier mapping
207
+ const consumerEvent = _.cloneDeep(consumer)
208
+
209
+ this.$dialog.success(this.$t('shared.forms.saved'))
210
+ this.$emit('update:consumer', consumerEvent)
211
+ } catch (e) {
212
+ this.$dialog.error(
213
+ this.$t('windward.integrations.shared.error.save_failed')
214
+ )
215
+ }
216
+ },
217
+ async onSave() {
218
+ if (this.formValid) {
219
+ await this.save()
220
+ }
221
+ },
222
+ },
223
+ }
224
+ </script>
@@ -22,7 +22,7 @@
22
22
  }}
23
23
  </v-expansion-panel-header>
24
24
  <v-expansion-panel-content>
25
- <!-- <ManageConsumers></ManageConsumers>-->
25
+ <ManageConsumers></ManageConsumers>
26
26
  </v-expansion-panel-content>
27
27
  </v-expansion-panel>
28
28
  </v-expansion-panels>
@@ -31,11 +31,11 @@
31
31
 
32
32
  <script>
33
33
  import ManageProviders from './Lti1p3/ManageProviders.vue'
34
- /* import ManageConsumers from './Lti1p3/ManageConsumers.vue' */
34
+ import ManageConsumers from './Lti1p3/ManageConsumers.vue'
35
35
 
36
36
  export default {
37
37
  name: 'ManageLti1p3Driver',
38
- components: { ManageProviders },
38
+ components: { ManageProviders, ManageConsumers },
39
39
  data() {
40
40
  return {
41
41
  panel: 0,
@@ -1,5 +1,12 @@
1
1
  <template>
2
- <v-text-field id="secret-field" :value="value" readonly :type="fieldType">
2
+ <v-text-field
3
+ id="secret-field"
4
+ :value="value"
5
+ readonly
6
+ :type="fieldType"
7
+ :placeholder="placeholder"
8
+ :label="label"
9
+ >
3
10
  <template #append>
4
11
  <v-btn icon @click="toggleClear">
5
12
  <v-icon>{{ showClear ? 'mdi-eye-off' : 'mdi-eye' }}</v-icon>
@@ -19,6 +26,14 @@ export default {
19
26
  value: { type: String, required: false, default: '' },
20
27
  hidden: { type: Boolean, required: false, default: true },
21
28
  copy: { type: Boolean, required: false, default: true },
29
+ placeholder: {
30
+ type: String,
31
+ required: false,
32
+ },
33
+ label: {
34
+ type: String,
35
+ required: false,
36
+ },
22
37
  },
23
38
  data() {
24
39
  return {