Skip to content

Instantly share code, notes, and snippets.

@udacityandroid
Created January 26, 2016 08:47
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save udacityandroid/996c56bf84eec19c53fb to your computer and use it in GitHub Desktop.
Save udacityandroid/996c56bf84eec19c53fb to your computer and use it in GitHub Desktop.
Firebase - Lesson 5 - Rules and Datastructure for Account Merge Example
{
"acknowledge" : {
"merges" : {
"accepted" : {
"898dac5d-f99d-463a-b82a-54abd5784447" : "google:106385094246122969144"
},
"proposed" : {
"898dac5d-f99d-463a-b82a-54abd5784447" : "google:106385094246122969144"
}
},
"messages" : {
"-K61_SOkAM3L8U8-DN97" : {
"timestamp" : 1450668578467,
"uid" : "google:106385094246122969144"
},
"-K652RtRKLRH2pjiBw25" : {
"timestamp" : 1450726772361,
"uid" : "google:106385094246122969144"
},
"-K65pKKz5ZwTPurw8fdw" : {
"timestamp" : 1450739848629,
"uid" : "google:106385094246122969144"
},
"-K65rVrEDWQce0oA-SQ3" : {
"timestamp" : 1450740420094,
"uid" : "google:106385094246122969144"
},
"-K65rZfG7TX5ko77Q5eY" : {
"timestamp" : 1450740435712,
"uid" : "google:106385094246122969144"
}
},
"users" : {
"4c9f4097-fe2d-4d22-8a17-b9480c2dc4e6" : {
"email" : "puf@puf.com",
"isTemporaryPassword" : false,
"profileImageURL" : "https://secure.gravatar.com/avatar/5ad89db23b9e5d5f00ba5548cc9e34ec?d=retro"
},
"898dac5d-f99d-463a-b82a-54abd5784447" : {
"email" : "frank@puf.com",
"isTemporaryPassword" : false,
"profileImageURL" : "https://secure.gravatar.com/avatar/4df6cf8a2fa4219b0990c579e3f5cffd?d=retro"
},
"google:106385094246122969144" : {
"accessToken" : "ya29.VAJtNRocmDS-eoWNpIxzKInpNsp9fIb5vWqINB2PTyizDJBhrPj_yd5BqFyndzuFvNmg3_E",
"cachedUserProfile" : {
"email" : "frank@puf.com",
"family_name" : "van Puffelen",
"gender" : "male",
"given_name" : "Frank",
"id" : "106385094246122969144",
"link" : "https://plus.google.com/+FrankvanPuffelen",
"locale" : "en",
"name" : "Frank van Puffelen",
"picture" : "https://lh3.googleusercontent.com/-5w08FC_pwUk/AAAAAAAAAAI/AAAAAAAAGio/aFRsRcln4bg/photo.jpg",
"verified_email" : true
},
"displayName" : "Frank van Puffelen",
"email" : "frank@puf.com",
"id" : "106385094246122969144",
"profileImageURL" : "https://lh3.googleusercontent.com/-5w08FC_pwUk/AAAAAAAAAAI/AAAAAAAAGio/aFRsRcln4bg/photo.jpg"
}
}
},
"pairing" : {
"merges" : {
"accepted" : {
"898dac5d-f99d-463a-b82a-54abd5784447" : "google:106385094246122969144"
}
},
"messages" : {
"-K6QOckahwR6H0GtOb4W" : {
"timestamp" : 1451084909670,
"uid" : "898dac5d-f99d-463a-b82a-54abd5784447"
},
"-K6W1RC_QpUWb9ASrqqu" : {
"timestamp" : 1451179492235,
"uid" : "898dac5d-f99d-463a-b82a-54abd5784447"
},
"-K6W2ANnHE75uqjtYWND" : {
"timestamp" : 1451179685465,
"uid" : "google:106385094246122969144"
}
},
"users" : {
"898dac5d-f99d-463a-b82a-54abd5784447" : {
"email" : "frank@puf.com",
"isTemporaryPassword" : false,
"profileImageURL" : "https://secure.gravatar.com/avatar/4df6cf8a2fa4219b0990c579e3f5cffd?d=retro"
},
"google:106385094246122969144" : {
"accessToken" : "ya29.VwK66CG-nQIJHva5zpi1YxcATWWEDriauAr6eNB_byKooF_k4KHKuykdfxAPw1DtmNsLtLw",
"cachedUserProfile" : {
"email" : "frank@puf.com",
"family_name" : "van Puffelen",
"gender" : "male",
"given_name" : "Frank",
"id" : "106385094246122969144",
"link" : "https://plus.google.com/+FrankvanPuffelen",
"locale" : "en",
"name" : "Frank van Puffelen",
"picture" : "https://lh3.googleusercontent.com/-5w08FC_pwUk/AAAAAAAAAAI/AAAAAAAAGio/aFRsRcln4bg/photo.jpg",
"verified_email" : true
},
"displayName" : "Frank van Puffelen",
"email" : "frank@puf.com",
"id" : "106385094246122969144",
"profileImageURL" : "https://lh3.googleusercontent.com/-5w08FC_pwUk/AAAAAAAAAAI/AAAAAAAAGio/aFRsRcln4bg/photo.jpg"
}
}
}
}
{
// This rules file contains two merging strategies:
// 1. acknowledge - requires user A to propose a merge and user B to accept it. Once accepted, the user A
// can only write messages which have user B as the uid.
// 2. pairings - User A generates a secret (that is written into the database) that they send to user B,
// user B enters the secret, which then starts the merge process of approach #1
"rules": {
"acknowledge": {
".read": true,
"users": {
"$uid": {
".write": "auth.uid == $uid"
}
},
"merges": {
// there are two lists here: proposed and accepted merges. Both are a mapping from uid of users A to uid of user B in the first explanation
"proposed": {
".indexOn": [".value"],
"$uid": {
// a merge can only be proposed by the current user
".write": "$uid == auth.uid"
}
},
"accepted": {
"$uid": {
// a merge can only be accepted by the user who is targetted in the merge and only when the merge has been proposed
".write": "auth.uid == newData.val() && newData.parent().parent().child('proposed').child($uid).val() == newData.val() "
}
}
},
"messages": {
// unmerged users can write messages under their own uid. Merged users can write messages under their merge target's uid.
"$messageid": {
".write": "(!newData.parent().parent().child('merges/accepted').child(auth.uid).exists() && auth.uid === newData.child('uid').val()) ||
( newData.parent().parent().child('merges/accepted').child(auth.uid).val() == newData.child('uid').val() )
"
}
}
},
"pairing": {
"users": {
".read": true,
"$uid": {
".write": "auth.uid == $uid"
}
},
"pairingCodes": {
// this node contains a list of pairing codes. The list itself is not readable, which prevents people from looking up all pairingCodes
"$code": {
// a pairing code consists of a uid and a timestamp. The uid identifies the user that generated the code.
".validate": "newData.hasChildren(['uid', 'timestamp'])",
// you can read a specific pairingCode if you know it and it's less than a minute old
".read": "data.child('timestamp').val() + 60000 > now",
// you can only write data if nothing exists yet, or delete existing data
".write": "(newData.exists() && !data.exists()) || (data.exists() && !newData.exists())",
"timestamp": {
".validate": "newData.val() == now"
}
}
},
"merges": {
// the rules for the merges are the same as in the first approach
".read": true,
"proposed": {
".indexOn": [".value"],
"$uid": {
".write": "$uid == auth.uid || newData.parent().parent().child('accepted').child($uid).val() == auth.uid"
}
},
"accepted": {
"$uid": {
".write": "auth.uid == newData.val() &&
data.parent().parent().child('proposed').child($uid).val() == newData.val() &&
!newData.parent().parent().child('proposed').child($uid).exists()
"
}
}
},
"messages": {
".read": true,
"$messageid": {
".write": "(!newData.parent().parent().child('merges/accepted').child(auth.uid).exists() && auth.uid === newData.child('uid').val()) ||
( newData.parent().parent().child('merges/accepted').child(auth.uid).val() == newData.child('uid').val() )
"
}
}
}
}
}
@ibrahimAlii
Copy link

ibrahimAlii commented Dec 18, 2016

Great Job :) ThnQ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment