-
Notifications
You must be signed in to change notification settings - Fork 4.1k
ENG-1365 - Adamk/roblox connection for students #7831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,16 @@ | ||||||||||||||||||||||||||||||||||||||||
const fetchJson = require('./fetch-json') | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
module.exports = { | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
post (options) { | ||||||||||||||||||||||||||||||||||||||||
if (options == null) { options = {} } | ||||||||||||||||||||||||||||||||||||||||
return fetchJson('/db/oauth2identity', _.assign({}, { | ||||||||||||||||||||||||||||||||||||||||
method: 'POST', | ||||||||||||||||||||||||||||||||||||||||
json: options, | ||||||||||||||||||||||||||||||||||||||||
})) | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+5
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance error handling and parameter validation The current implementation could benefit from several improvements:
Consider this implementation: - post (options) {
- if (options == null) { options = {} }
- return fetchJson('/db/oauth2identity', _.assign({}, {
- method: 'POST',
- json: options,
- }))
+ post (options = {}) {
+ if (typeof options !== 'object') {
+ throw new TypeError('Options must be an object')
+ }
+ return fetchJson('/db/oauth2identity', {
+ method: 'POST',
+ json: options,
+ }).catch(error => {
+ console.error('Failed to post OAuth2 identity:', error)
+ throw error
+ })
+ } 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
fetchForProviderAndUser (provider, userId) { | ||||||||||||||||||||||||||||||||||||||||
return fetchJson('/db/oauth2identity/by-user', { data: { userId, provider } }) | ||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
<script> | ||
import VueConfirmDialog from 'vue-confirm-dialog' | ||
import oauth2identity from 'core/api/oauth2identity' | ||
|
||
Vue.use(VueConfirmDialog) | ||
Vue.component('VueConfirmDialog', VueConfirmDialog.default) | ||
|
||
export default Vue.extend({ | ||
props: { | ||
userId: { | ||
type: String, | ||
required: true, | ||
}, | ||
}, | ||
data () { | ||
return { | ||
isAnonymous: me.isAnonymous(), | ||
robloxID: '', | ||
} | ||
}, | ||
Comment on lines
+15
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add missing import and Roblox ID validation. The component uses
import Vue from 'vue'
import VueConfirmDialog from 'vue-confirm-dialog'
import oauth2identity from 'core/api/oauth2identity'
+import { me } from 'core/utils'
+ computed: {
+ isValidRobloxID() {
+ return /^\d+$/.test(this.robloxID.trim())
+ }
+ },
|
||
|
||
methods: { | ||
async createNewIdentity () { | ||
await oauth2identity.post({ | ||
ownerID: this.userId, | ||
provider: 'roblox', | ||
profile: { | ||
sub: this.robloxID, | ||
}, | ||
}) | ||
}, | ||
async onSave () { | ||
if (this.robloxID) { | ||
this.$refs.connectRobloxButton.disabled = true | ||
try { | ||
await this.createNewIdentity() | ||
this.$emit('saved') | ||
} catch (error) { | ||
noty({ | ||
text: error.message, | ||
type: 'error', | ||
timeout: 5000, | ||
}) | ||
this.$refs.robloxID.select() | ||
} finally { | ||
if (this.$refs.connectRobloxButton) { | ||
this.$refs.connectRobloxButton.disabled = false | ||
} | ||
} | ||
} | ||
}, | ||
}, | ||
Comment on lines
+22
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enhance security and robustness of the save operation. Several improvements can be made to the methods implementation:
Apply these changes: methods: {
async createNewIdentity () {
+ const sanitizedID = this.robloxID.trim()
+ if (!this.isValidRobloxID) {
+ throw new Error(this.$t('account_settings.invalid_roblox_id'))
+ }
await oauth2identity.post({
ownerID: this.userId,
provider: 'roblox',
profile: {
- sub: this.robloxID,
+ sub: sanitizedID,
},
})
},
async onSave () {
- if (this.robloxID) {
- this.$refs.connectRobloxButton.disabled = true
+ if (this.robloxID.trim()) {
+ this.isLoading = true
try {
await this.createNewIdentity()
this.$emit('saved')
} catch (error) {
+ const errorMessage = error.response?.status === 409
+ ? this.$t('account_settings.roblox_id_already_connected')
+ : this.$t('account_settings.connection_error')
noty({
- text: error.message,
+ text: errorMessage,
type: 'error',
timeout: 5000,
})
this.$refs.robloxID.select()
} finally {
- if (this.$refs.connectRobloxButton) {
- this.$refs.connectRobloxButton.disabled = false
- }
+ this.isLoading = false
}
}
},
}, Don't forget to add the loading state to the data: data () {
return {
isAnonymous: me.isAnonymous(),
robloxID: '',
+ isLoading: false,
}
},
|
||
}) | ||
</script> | ||
|
||
<template> | ||
<div class="roblox-id form-inline"> | ||
<div class="form-group"> | ||
<input | ||
ref="robloxID" | ||
v-model="robloxID" | ||
type="text" | ||
class="roblox-id__input form-control" | ||
placeholder="Roblox ID" | ||
> | ||
<button | ||
ref="connectRobloxButton" | ||
class="btn form-control btn-primary" | ||
@click="onSave" | ||
> | ||
{{ $t('account_settings.connect_roblox_button') }} | ||
</button> | ||
</div> | ||
</div> | ||
</template> | ||
Comment on lines
+56
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance template with validation feedback and accessibility. The template needs improvements for better user experience and accessibility. <template>
<div class="roblox-id form-inline">
<div class="form-group">
<input
ref="robloxID"
v-model="robloxID"
type="text"
class="roblox-id__input form-control"
+ :class="{ 'is-invalid': robloxID && !isValidRobloxID }"
placeholder="Roblox ID"
+ aria-label="Roblox ID"
+ :aria-invalid="!isValidRobloxID"
>
+ <div v-if="robloxID && !isValidRobloxID" class="invalid-feedback">
+ {{ $t('account_settings.invalid_roblox_id') }}
+ </div>
<button
ref="connectRobloxButton"
- class="btn form-control btn-primary"
+ class="btn form-control btn-primary"
+ :disabled="isLoading || !isValidRobloxID"
@click="onSave"
+ aria-label="Connect Roblox Account"
>
- {{ $t('account_settings.connect_roblox_button') }}
+ <span v-if="isLoading">
+ <i class="fa fa-spinner fa-spin"></i>
+ </span>
+ <span v-else>
+ {{ $t('account_settings.connect_roblox_button') }}
+ </span>
</button>
</div>
</div>
</template>
|
||
|
||
<style lang="scss" scoped> | ||
.roblox-id { | ||
width: 100%; | ||
.form-group { | ||
display: flex; | ||
gap: 15px; | ||
.roblox-id__input { | ||
width: 100%; | ||
} | ||
} | ||
} | ||
</style> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add missing lodash import
The code uses
_.assign
but lodash is not imported. This will cause a runtime error.Add the following import at the top of the file:
const fetchJson = require('./fetch-json') +const _ = require('lodash')
📝 Committable suggestion