diff --git a/client/src/app/user-profile/import-user-profile/import-user-profile.component.css b/client/src/app/user-profile/import-user-profile/import-user-profile.component.css index 3383624c0..14a4ec4f6 100644 --- a/client/src/app/user-profile/import-user-profile/import-user-profile.component.css +++ b/client/src/app/user-profile/import-user-profile/import-user-profile.component.css @@ -5,4 +5,7 @@ } paper-input { margin: 15px; -} \ No newline at end of file +} +#err { + color: red; + } \ No newline at end of file diff --git a/client/src/app/user-profile/import-user-profile/import-user-profile.component.html b/client/src/app/user-profile/import-user-profile/import-user-profile.component.html index 71ad6c915..0841d0010 100644 --- a/client/src/app/user-profile/import-user-profile/import-user-profile.component.html +++ b/client/src/app/user-profile/import-user-profile/import-user-profile.component.html @@ -3,5 +3,11 @@ {{'submit'|translate}}

- {{'Syncing'|translate}}... + {{'Synced'|translate}} {{processedDocs}} {{'of'|translate}} {{totalDocs}} +

+

+ {{'Record with import code'|translate}} {{shortCode}} {{'not found.'|translate}} +

+

+ {{'Import not successful. Click Submit to retry.' |translate}}

diff --git a/client/src/app/user-profile/import-user-profile/import-user-profile.component.ts b/client/src/app/user-profile/import-user-profile/import-user-profile.component.ts index a88533c08..971a5aeba 100644 --- a/client/src/app/user-profile/import-user-profile/import-user-profile.component.ts +++ b/client/src/app/user-profile/import-user-profile/import-user-profile.component.ts @@ -17,9 +17,16 @@ export class ImportUserProfileComponent implements AfterContentInit { STATE_SYNCING = 'STATE_SYNCING' STATE_INPUT = 'STATE_INPUT' + STATE_ERROR = 'STATE_ERROR' + STATE_NOT_FOUND ='STATE_NOT_FOUND' appConfig: AppConfig state = this.STATE_INPUT docs; + totalDocs; + processedDocs = 0; + userAccount; + db; + shortCode @ViewChild('userShortCode', {static: true}) userShortCodeInput: ElementRef; constructor( @@ -27,32 +34,52 @@ export class ImportUserProfileComponent implements AfterContentInit { private http: HttpClient, private userService: UserService, private appConfigService: AppConfigService - ) { } + ) { } ngAfterContentInit() { } async onSubmit() { const username = this.userService.getCurrentUser() - const db = await this.userService.getUserDatabase(this.userService.getCurrentUser()) - const userAccount = await this.userService.getUserAccount(this.userService.getCurrentUser()) + this.db = await this.userService.getUserDatabase(username) + this.userAccount = await this.userService.getUserAccount(username) try { - const profileToReplace = await db.get(userAccount.userUUID) - await db.remove(profileToReplace) + const profileToReplace = await this.db.get(this.userAccount.userUUID) + await this.db.remove(profileToReplace) } catch(e) { // It's ok if this fails. It's probably because they are trying again and the profile has already been deleted. } - this.state = this.STATE_SYNCING - this.appConfig = await this.appConfigService.getAppConfig() - const shortCode = this.userShortCodeInput.nativeElement.value - this.docs = await this.http.get(`${this.appConfig.serverUrl}api/${this.appConfig.groupId}/responsesByUserProfileShortCode/${shortCode}`).toPromise() - const newUserProfile = this.docs.find(doc => doc.form && doc.form.id === 'user-profile') - await this.userService.saveUserAccount({...userAccount, userUUID: newUserProfile._id, initialProfileComplete: true}) - for (let doc of this.docs) { - delete doc._rev - await db.put(doc) - } - this.router.navigate([`/${this.appConfig.homeUrl}`] ); + await this.startSyncing() + } + + async startSyncing(){ + try { + this.appConfig = await this.appConfigService.getAppConfig() + this.shortCode = this.userShortCodeInput.nativeElement.value; + let newUserProfile = await this.http.get(`${this.appConfig.serverUrl}/api/${this.appConfig.groupId}/responsesByUserProfileShortCode/${this.shortCode}/?userProfile=true`).toPromise() + if(!!newUserProfile){ + this.state = this.STATE_SYNCING + await this.userService.saveUserAccount({ ...this.userAccount, userUUID: newUserProfile['_id'], initialProfileComplete: true }) + this.totalDocs = (await this.http.get(`${this.appConfig.serverUrl}/api/${this.appConfig.groupId}/responsesByUserProfileShortCode/${this.shortCode}/?totalRows=true`).toPromise())['totalDocs'] + const docsToQuery = 1000; + let processedDocs = +localStorage.getItem('processedDocs') || 0; + while (processedDocs < this.totalDocs) { + this.docs = await this.http.get(`${this.appConfig.serverUrl}/api/${this.appConfig.groupId}/responsesByUserProfileShortCode/${this.shortCode}/${docsToQuery}/${processedDocs}`).toPromise() + for (let doc of this.docs) { + delete doc._rev + await this.db.put(doc) + } + processedDocs += this.docs.length; + this.processedDocs = processedDocs + localStorage.setItem('processedDocs', String(processedDocs)) + } + } else{ + this.state = this.STATE_NOT_FOUND + } + this.router.navigate([`/${this.appConfig.homeUrl}`] ); + } catch (error) { + this.state = this.STATE_ERROR + } } -} +} \ No newline at end of file diff --git a/server/src/group-views.js b/server/src/group-views.js index 5d9690cb3..1d8e7725f 100644 --- a/server/src/group-views.js +++ b/server/src/group-views.js @@ -77,6 +77,12 @@ module.exports.responsesByUserProfileShortCode = function(doc) { } } +module.exports.userProfileByUserProfileShortCode = function (doc) { + if (doc.collection === "TangyFormResponse"&&doc.form && doc.form.id === 'user-profile') { + return emit(doc._id.substr(doc._id.length - 6, doc._id.length), true); + } +} + module.exports.groupIssues = function(doc) { if (doc.collection === "TangyFormResponse" && doc.type === "issue") { var lastFilledOutNode; @@ -214,4 +220,4 @@ module.exports.byConflictDocId = { emit(doc.conflictDocId, doc.conflictRev); }.toString(), reduce: '_count' -} \ No newline at end of file +} diff --git a/server/src/routes/group-responses-by-user-profile-short-code.js b/server/src/routes/group-responses-by-user-profile-short-code.js index 2bf65f469..9f397bef5 100644 --- a/server/src/routes/group-responses-by-user-profile-short-code.js +++ b/server/src/routes/group-responses-by-user-profile-short-code.js @@ -5,17 +5,32 @@ const log = require('tangy-log').log module.exports = async (req, res) => { try { const groupDb = new DB(req.params.groupId) - let options = {key: req.params.userProfileShortCode, include_docs: true} + const userProfileShortCode = req.params.userProfileShortCode + let options = { key: userProfileShortCode, include_docs: true } if (req.params.limit) { options.limit = req.params.limit } if (req.params.skip) { options.skip = req.params.skip } - const results = await groupDb.query('responsesByUserProfileShortCode', options); - const docs = results.rows.map(row => row.doc) - res.send(docs) + if (req.query.totalRows) { + options.limit = 1 + options.skip = 0 + const results = await groupDb.query('responsesByUserProfileShortCode', options); + res.send({ totalDocs: results.total_rows }) + } else if (req.query.userProfile) { + await groupDb.query("userProfileByUserProfileShortCode", { limit: 0 }); + const result = await groupDb.query("userProfileByUserProfileShortCode", { key: userProfileShortCode, limit: 1, include_docs: true }); + const profile = result.rows[0] + const data = profile ? {_id: profile.id, key: profile.id, formId: profile.doc.form.id, collection: profile.doc.collection}: undefined + res.send(data) + } else { + const results = await groupDb.query('responsesByUserProfileShortCode', options); + const docs = results.rows.map(row => row.doc) + res.send(docs) + } } catch (error) { + console.log(error) log.error(error); res.status(500).send(error); }