const functions = require('firebase-functions'); const admin = require('firebase-admin'); let key = "./serviceAccountKey.json"; if(process.env.GCLOUD_PROJECT === "monkey-type"){ key = "./serviceAccountKey_live.json" } var serviceAccount = require(key); admin.initializeApp({ credential: admin.credential.cert(serviceAccount) }); // // Create and Deploy Your First Cloud Functions // // https://firebase.google.com/docs/functions/write-firebase-functions // // exports.helloWorld = functions.https.onRequest((request, response) => { // response.send("Hello from Firebase!"); // }); exports.moveResults = functions.runWith({timeoutSeconds:540,memory: '2GB'}).https.onCall((request,response) => { return admin.firestore().collection('results').orderBy('timestamp','desc').limit(2000).get().then(data => { data.docs.forEach(doc => { let result = doc.data(); if(result.moved === undefined || result.moved === false){ admin.firestore().collection(`results`).doc(doc.id).update({moved:true}); admin.firestore().collection(`users/${result.uid}/results`).add(result); console.log(`moving doc ${doc.id}`); } }) return }) }) function getAllNames(){ return admin.auth().listUsers().then(data=>{ let names = []; data.users.forEach(user =>{ names.push(user.displayName); }) return names; }) } function getAllUsers(){ return admin.auth().listUsers().then(data=>{ return data.users; }) } function isUsernameValid(name){ if(name === null || name === undefined || name === "") return false; if(/miodec/.test(name)) return false; if(name.length > 12) return false; return /^[0-9a-zA-Z_.-]+$/.test(name); } exports.checkNameAvailability = functions.https.onCall((request,response) => { try{ if(!isUsernameValid(request.name)) return 0; return getAllNames().then(data => { let available = 1; data.forEach(name =>{ try{ if(name.toLowerCase() === request.name.toLowerCase()) available = 0; }catch(e){ // } }) return available; }); }catch(e){ return -1; } }) exports.changeName = functions.https.onCall((request,response) => { try{ if(!isUsernameValid(request.name)){ console.warn(`${request.uid} tried to change their name to ${request.name} - not valid`); return 0; } return getAllNames().then(data => { let available = 1; data.forEach(name =>{ try{ if(name.toLowerCase() === request.name.toLowerCase()) available = 0; }catch(e){ // } }) if(available === 1){ return admin.auth().updateUser(request.uid,{ displayName: request.name }).then(d => { console.log(`${request.uid} changed their name to ${request.name} - done`); return 1; }).catch(e => { console.error(`${request.uid} tried to change their name to ${request.name} - ${e}`); return -1; }) }else{ console.warn(`${request.uid} tried to change their name to ${request.name} - already taken`); return 0; } }); }catch(e){ console.error(`${request.uid} tried to change their name to ${request.name} - ${e}`); return -1; } }) exports.checkIfNeedsToChangeName = functions.https.onCall((request,response) => { try{ return admin.auth().getUser(request.uid).then(requestUser => { if(!isUsernameValid(requestUser.displayName)){ //invalid name, needs to change console.log(`user ${requestUser.uid} ${requestUser.displayName} needs to change name`); return 1; }else{ //valid name, but need to change if not duplicate return getAllUsers().then(users => { let sameName = []; //look for name names users.forEach(user => { if (user.uid !== requestUser.uid){ try{ if(user.displayName.toLowerCase() === requestUser.displayName.toLowerCase()){ sameName.push(user); } }catch(e){ // } } }) if(sameName.length === 0){ return 0 }else{ //check when the request user made the account compared to others let earliestTimestamp = 999999999999999; sameName.forEach(sn => { let ts = (new Date(sn.metadata.creationTime).getTime() / 1000); if(ts <= earliestTimestamp){ earliestTimestamp = ts; } }) if((new Date(requestUser.metadata.creationTime).getTime() / 1000) > earliestTimestamp){ console.log(`user ${requestUser.uid} ${requestUser.displayName} needs to change name`); return 2; }else{ return 0; } } }) } }); }catch(e){ return -1; } }) function checkIfPB(uid,obj){ return admin.firestore().collection(`users`).doc(uid).get().then(data => { let pbs = null; try{ pbs = data.data().personalBests; }catch(e){ return admin.firestore().collection('users').doc(uid).update({ personalBests: { [obj.mode]: { [obj.mode2]: [{ language: obj.language, difficulty: obj.difficulty, punctuation: obj.punctuation, wpm: obj.wpm }] } } }).then(e => { return true; }).catch(e => { return admin.firestore().collection('users').doc(uid).set({ personalBests: { [obj.mode]: { [obj.mode2]: [{ language: obj.language, difficulty: obj.difficulty, punctuation: obj.punctuation, wpm: obj.wpm }] } } }).then(e => { return true; }) }) } // //check mode, mode2, punctuation, language and difficulty let toUpdate = false; let found = false; try{ pbs[obj.mode][obj.mode2].forEach(pb => { if( pb.punctuation === obj.punctuation && pb.difficulty === obj.difficulty && pb.language === obj.language){ //entry like this already exists, compare wpm found = true; if(pb.wpm < obj.wpm){ //new pb pb.wpm = obj.wpm; toUpdate = true; }else{ //no pb return false; } } }) //checked all pbs, nothing found - meaning this is a new pb if(!found){ pbs[obj.mode][obj.mode2].push({ language: obj.language, difficulty: obj.difficulty, punctuation: obj.punctuation, wpm: obj.wpm }) toUpdate = true; } }catch(e){ // console.log(e); pbs[obj.mode] = {}; pbs[obj.mode][obj.mode2] = [{ language: obj.language, difficulty: obj.difficulty, punctuation: obj.punctuation, wpm: obj.wpm }]; toUpdate = true; } if(toUpdate){ return admin.firestore().collection('users').doc(uid).update({personalBests: pbs}).then(e => { return true; }); }else{ return false; } }) } exports.testCompleted = functions.https.onCall((request,response) => { try{ if(request.uid === undefined || request.obj === undefined){ console.error(`error saving result for ${request.uid} - missing input`); return -1; } let obj = request.obj; let err = false; Object.keys(obj).forEach(key => { let val = obj[key]; if(Array.isArray(val)){ val.forEach(valarr => { if(!/^[0-9a-zA-Z._]+$/.test(valarr)) err = true; }) }else{ if(val === undefined || !/^[0-9a-zA-Z._]+$/.test(val)) err = true; } }) if (err){ console.error(`error saving result for ${request.uid} - bad input`); return -1; } if (obj.wpm <= 0 || obj.wpm > 350 || obj.acc < 50 || obj.acc > 100){ return -1; } return admin.firestore().collection(`users/${request.uid}/results`).add(obj).then(e => { // return 1; return checkIfPB(request.uid,request.obj).then(e => { if(e){ return 2; }else{ return 1; } }); }).catch(e => { console.error(`error saving result for ${request.uid} - ${e}`); return -1; }); }catch(e){ console.error(`error saving result for ${request.uid} - ${e}`); return -1; } })