Best practice for friend-adding system with Firebase? - ios

I'm trying to think of the best way to structure a database to allow users to send/accept/decline users as friends.
I've currently got a system that allows users to search through users, checks all the necessary stuff like people already being on their list bhalbhla, but I don't know how to finish it off with actually sending the invites.
My structure looks like:
Users
290384239843
friends:
093824098209384: true
username: Bob
Usernames
Bob: 290384239843
I figure when I hit the add button, it sends something to both users on Firebase, and I think the two options are:
users
29038493
friends
0283940839024: pending
or
users
02938409384
friends
3094809384903 : true
pendingFriends:
0283940839024: true
I think both could potentially work, but I figured I'd reach out incase I could get some guidance from someone with more experience with this. Maybe there's a better way entirely different?

Both your options look good to me.
You have to think about where you want this information regarding "friend requests" to be displayed in your app and if you need it displayed in other ways (like see all pending friend requests or see all the friend requests a user has sent out) and duplicate the request data to all the nodes you need.
You can also use, instead of status = "pending" a simple true \ false value.
True = friends
False = not approved
Null = does not exist

Related

Trello API (Ruby/Rails) getting user's cards, boards, lists

I want to get particular data from Trello (using Trello API) knowing only user's trello id. I need to get all user's cards that has particular list names, and for all cards that meets requirements I need to get: card shortLink, list name, board name. The problem is I need to reduce waiting time. The only reasonable solution is to use less API requests. Here is my code:
userCards = JSON.parse(#a.get('/members/'+trello_id+'/cards?fields=shortLink,labels').body)
userCards.each do |card|
list = JSON.parse(#a.get('/cards/'+card['id']+'/list?fields=name').body)
if LIST.include?(list['name'].upcase)
board = JSON.parse(#a.get('/cards/'+card['id']+'/board?fields=name').body)
end
end
If you have any idea how to make this code work faster, I will be more than happy to hear that.

Handling URLs that change

If an example website contains blog posts created by users this would be an easy way to structure the URLs for each post:
www.example.com/jane-smith/my-first-blog-post
If the user was to change their username (which is unique per user) or the title of their blog post the URL would have to change to be updated. For example if the above user changed her username the URL could be like so:
www.example.com/jane-wilson/my-first-blog-post
A problem now arises as if people try to use the old URL, it would not work. How could this situation be avoided or worked around for an existing website without removing the feature to change usernames or blog post names?
A common way is to include a unique ID which never changes (for users and posts, in your case), and then 301-redirect to the current/canonical variant.
Example
This is what, for example, Stack Overflow is doing.
If you change your question’s title, the ID (36463097) will stay and the slug will change:
https://stackoverflow.com/questions/36463097/handling-urls-that-change
https://stackoverflow.com/questions/36463097/handling-urls-that-might-change
If you change your user name, the ID (2961662) will stay and the slug will change:
https://stackoverflow.com/users/2961662/psidhu
https://stackoverflow.com/users/2961662/john-doe
This also allows to have users with the same user name (in case you want to allow that):
http://example.com/23/john-doe
http://example.com/42/john-doe
Drawbacks
It’s not the best URL design:
/users/2961662/psidhu is not as beautiful as /users/psidhu
remembering a URL with such a cryptic ID is hard(er)
such an ID is not meaningful, so ideally it wouldn’t be part of the URL
Alternative
Track all changes and block user names that were once registered. So If I start as john and then change my name to john-doe, no one else may register john.
This is good practice for email addresses, and in my opinion it should also be good practice for every service that allows direct communication with users. If users get messages intended for the previous owner of that user name, that’s a serious problem; if users don’t get their favorite user name because someone else registered it before, it’s, at most, annoying.
So for each user you could track previous user names, and for each post previous titles, and then 301-redirect to the current/canonical one.

How to create a "backdoor" for administrator, to be able to log in as anohter user and see information?

I am creating an online survey tool.
As an administrator, i would like to see what the users have answered and also be able to answer on their behalf. The system get's a users answers and other information based on his/her username, when they are logged in, using the built in membership provider.
There are currently three roles: Administrator, Moderator and Respondent
If i would like to show my administrator a list of users,
how would it be possible to create a "backdoor" for the administrator, so that he can "log" in as the user, see the users answers etc ? (Just like the user would be able to if he was logged in to his own account).
When answering and retrieving quyestions, the system is bound to `User.Identity.Name
My suggestion on how to solve this:
Currently, when i want to retrive a users answers i use the following code:
Firma_ID = db.Firma.Single(x => x.CVR_nummer == User.Identity.Name).firma_id;
var answers = db.Tabelform_Answers.Where(x => x.question_id == model.Question_ID && x.respondent == Firma_ID);
This is because i have a table named Firma, that has a column referencing to a users Name, called CVR_Nummer. I then retrieve all the records in the Tabelform_Answers table, that match question_id and Firma_ID (A users answers for a specific question).
Instead of using `Firma_ID = db.Firma.Single(x => x.CVR_nummer == User.Identity.Name).firma_id;
to retrive the Firma_ID of a given user, i could store it in the Session upon Login. When i want to view a specific users Answers as Administrator, i would then just change Firma_ID in the Session. Changing Firma_ID in the Session would only be allowed through a controller which has the following code:
[Authorize(Roles = "Administrator")]
Also, i would set the Session timeout to be the same as the Authentication timeout.
Can somebody tell me which pros and cons of this solution? Are there any other ways of storing a "global" variable for a Session? (Firma_ID)?
Thanks
If you only need to log in as your users, I went for a ticket-method.
I have a special login-page that can take a ticket-id. This ticket is created in the admin-gui when the admin wants to log in as another user. The login-page checks the ticket in the database, logs in the wanted user, and then deletes/marks the ticket as used. As an added security, a ticket is only valid for 10 seconds after creation.
Another option is to make answers from users available from the admin-gui...
also you can do in your log-in script override
so you have at present something like
if user name and password match string then user is logged in and based on this you get user permissions
instead have admin page,
where you can select user and then you can apply permissions of the user instead of admin.

How could I display a *specific* user's information through an instance variable in Ruby on Rails?

This is the code I'm currently using:
profile_controller.rb:
#user = User.first :conditions => [ "lower(username) = ?", params[:id].downcase ]
show.html.haml:
.footer #{#user.bets.count} -# This displays 0, even though I can see that the user has multiple bets associated with his username in the db
My users sign in with Twitter and their usernames could be in any case variation (e.g. BOB, bob, BoB, Bob etc.) - and naturally, any information associated with their username should be accordingly displayed regardless of how the users have signed in.
One strange bug I'm running into is that all associated information with the username seems to be lost once a user signs out, and signs back in; however, this happens seemingly at random times. That is, a user can sign out and sign back in several times without issue, but once in a while, seems to lose all associated information in the profile.
Any tips on how I could go about ensuring this isn't the case? Is the controller code I posted correct, or should I be checking for another parameter other than param[:id]?
EDIT: Thanks for the comments, guys. It turns out that I was overwriting the user information if they just sign in with different case variations. I cleaned this up, and it works now.
Perhaps you are looking to do something like:
#user = User.where(:username => params[:username].downcase).first
You could try explicitly including the bets when retrieving the user:
#user = User.includes(:bets).where("lower(username) = ?", params[:id].downcase).first
which will automatically retrieve all related bets.
Normally using #user.bets it is lazy loaded, but once it is loaded, it just uses the bets in memory. To explicitly load all bets again from database, you could also write:
#user.bets.reload.count

Get age of friend on Facebook with Ruby via rFacebook

I am creating a Facebook app and need to access people's ages - only the friends of the user, not the general public.
I am using rFacebook version 0.6.2, setup along the line of this.
I need to get the ages/ birthdays of all of my friends.
As per http://rfacebook.rubyforge.org/ rFacebook isnt being maintained, it suggested Facebooker, but even Facebooker hasn't been updated in months: https://github.com/mmangino/facebooker
I suggest Koala (and not just because I'm an Aussie). Have a read at: https://github.com/arsduo/koala There's also details on setting Koala up on Rails: https://github.com/arsduo/koala/wiki/Koala-on-Rails
I just built a FB app using Koala and a Custom Tab Page last week and it was very quick.
You also need to read: http://developers.facebook.com/docs/authentication/ (pay attention to the mention of scopes and permission levels). As per: http://developers.facebook.com/docs/authentication/permissions/ you must request 'friends_birthday' when you request your scope.
I'm not sure there is an easy way to get all your friends' birthdays in a batch. You might have to traverse each friend and get their info.
As a test, go to: http://developers.facebook.com/docs/reference/api/ and click on the friends link. Then copy the ID of your first friend. In the URL replace '/me/friends' with the ID you copied. Eg: https://graph.facebook.com/me/friends?access_token=ABC123 becomes https://graph.facebook.com/12345678?access_token=ABC123 You will then see the data of that friend, one field of which is birthday.
#i have already asked for user permissions, and have my access token
#https://github.com/arsduo/koala/wiki/OAuth
graph = Koala::Facebook::GraphAPI.new(oauth_access_token)
friends = graph.get_connections("me", "friends")
friends.each do |f|
friend = graph.get_object(f['id'])
puts "#{f['name']} has a birthday on #{friend["birthday"]}"
end
Although, you might be able to use FQL to do a batch.
#FQL taken from http://stackoverflow.com/questions/5063431/easiest-way-to-get-birthday-info-of-all-friends-thorugh-graph-api
fql = "select uid,name,birthday_date from user where uid in (select uid2 from friend where uid1=me())"
#https://github.com/arsduo/koala/wiki/REST-API
#rest = Koala::Facebook::GraphAndRestAPI.new(oauth_access_token)
birthdays = #rest.fql_query(fql)
Good luck!
FQL is probably the way to go here as is mentioned above.
A couple notes:
Not all of your friends will have a birthday accessible (either because they restricted that information, or because they didn't post it). If you only want data for your friends with accessible birthdays, you can add a "and birthday_date" to your where clause.
That query will not return all data, but only the first 100 or so. If you want to get all of them, you will need to request them one page at a time. You can do this by adding a "limit 0,50" clause, to request 50 rows, starting at the 0th one.

Resources