Check for duplicates before insertion in Firebase - android

I am new to Firebase and I trying to implement it into an Android application. It was all going well until now. I have to check the records for duplicates before inserting them and even after the tons of tutorials I watched online I can't figure it out.
I tried with rules, but apparently I was not able to write them down in a way they would work. I tried with push(), but this was not working either.
At the moment this is the code that I have:
private void updateDatabase(String year, String courseOfStudent, String workshopGroup, String day, String time, String lecture){
try{
mDatabase.child("student-timetables").child("course-of-student").setValue(courseOfStudent);
mDatabase.child("student-timetables").child(courseOfStudent).child("year").setValue(year);
mDatabase.child("student-timetables").child(courseOfStudent).child(year).child("workshop-group").setValue(workshopGroup);
mDatabase.child("student-timetables").child(courseOfStudent).child(year).child(workshopGroup).child("day").setValue(day);
mDatabase.child("student-timetables").child(courseOfStudent).child(year).child(workshopGroup).child(day).child("time").setValue(time);
mDatabase.child("student-timetables").child(courseOfStudent).child(year).child(workshopGroup).child(day).child(time).child("lecture").setValue(lecture);}
catch (Exception e)
{
Toast.makeText(getContext(), "Internal error occurred, please try again.", Toast.LENGTH_LONG).show();
}
}
And the rules from the Firebase console:
{
"rules": {
".read": "true",
".write": "auth != null",
"course-of-student": {
"year": {
"workshop-group": {
"day":{
"time": {
".write": "!data.exists()"
}
}
}
}
}
}
}
As of now what happens is that if there is a lecture detail at a specific time and I try to create a new record for this time the previous one gets overwritten. I want to reject this and display a message instead.
Where am I wrong?

First, add "ListenerForSingleValueEvent", and only then save the data in Firebase (if not exist..)
For example:
mDatabase.child("student-timetables").child(courseOfStudent).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if(!(snapshot.child("year").exist))
mDatabase.child("student-timetables").child(courseOfStudent).child("year").setValue(year);
else
Toast.maketext....."year exist.."
if(!(snapshot.child(year).child("workshop-group").exist))
mDatabase.child("student-timetables").child(courseOfStudent).child(year).child("workshop-group").setValue(workshopGroup);
else
Toast.maketext....."workshopGroup exist.."
}
}

Related

firestore: let users update, delete only their own data

These are my current security rules:
service cloud.firestore {
match /databases/{database}/documents {
match /tournaments/{tournament=**} {
allow update, delete: if request.auth.uid == resource.data.author;
allow create: if request.auth.uid != null;
allow read: if true;
}
}
}
Everything is working, only updating or deleting does not work due to "Missing or insufficient permissions"
Here is my code for that
mDocRef
.update(key, score)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "DocumentSnapshot successfully updated!");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error updating document", e);
}
});
mDocRef refers to a document with a path of "tournaments/tournamentID/aColletion/aDocument"
Here is the code to create mDocRef:
mTournamentDocRef = mTournamentColRef.document();
mDocRef = mTournamentDocRef.collection("aCollection").document();
Some things to note:
the user is during the whole process signed in through firebase
I tried using .where("author", "==", user.uid) but got an "cannot resolve method" error
Thank you for your help!
I checked the documentation, those are the rules you are looking for:
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
And the documentation link as a reference: https://firebase.google.com/docs/firestore/security/rules-conditions?authuser=0
I added the ID of the firebase user to each document that is created to get the wanted results
tournamentData.put("author", user.getUid());
data.put("author", user.getUid());

how to access added parameter in branch deep linking

This question is not a duplication of this question.I have tried the solution mentioned there but didn't get any luck.
I have added branch.io deep-linking to my app. To test the implementation I have created a link with parameter as described here
https://docs.branch.io/pages/apps/android/#test-deep-link
everything worked fine, but the problem is I can not access the added data from the json object as the json doesn't contain the key I added earlier. I was supposed to get a response like this:
{
"identity_id": "427469360685348303",
"link": "https://example.app.link?%24identity_id=427469360685348303",
"session_id": "429691081177874743",
"data": {
"$canonical_identifier": "item/1503684554354.28",
"$desktop_url": "http://example.com/home",
"$exp_date": 0,
"$identity_id": "427469360685348303",
"$og_description": "My Content Description",
"$og_image_url": "http://lorempixel.com/200/200/",
"$og_title": "46D6D28E-0390-40E4-A856-BD74F34D24C8",
"$publicly_indexable": 1,
"+click_timestamp": 1503684563,
"+clicked_branch_link": true,
"+is_first_session": false,
"+match_guaranteed": true,
"custom": "blue",
"random": "FE848A5B-78F7-42EC-A253-9F795FE91692",
"added": "1503684554354.33",
"~campaign": "new launch",
"~channel": "facebook",
"~creation_source": 3,
"~feature": "sharing",
"~id": 429691043152332059,
"~referring_link": "https://example.app.link/X7OsnWv9TF",
"~stage": "new person",
"~tags": [
"one",
"two"
]
}
}
But this the response I got:
{"+non_branch_link":"https:\/\/qr6x.test-app.link\/g5ynWCX7PI","+clicked_branch_link":false,"+is_first_session":false}
here is my code:
Branch branch = Branch.getInstance(context);
branch.initSession(new Branch.BranchReferralInitListener() {
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
if (error == null) {
// params are the deep linked params associated with the link that the user clicked -> was re-directed to this app
// params will be empty if no data found
// ... insert custom logic here ...
try {
Log.e("myapp","no error");
Log.e("myapp", referringParams.toString());
String pictureID = referringParams.optString("asdasdasdasd", "");
if (pictureID.equals("")) {
Log.e("myapp","no ID");
}
else {
Log.e("myapp","ID "+pictureID);
}
} catch (Exception e) {
System.out.println(" " + e.toString());
}
} else {
Log.i("MyApp", error.getMessage());
}
}
}, intent.getData(), activity);
can anyone give any idea what I am doing wrong?
Jackie from Branch here.
The +non_branch_link typically happens whenever there is an error when creating a Branch Deep Link, or whenever the live_key/test_key get mixed up (i.e. clicking a test link with an app that's using your live key, or vice versa).
Can you confirm that you have the correct Branch test key in the AndroidManifest.xml of your staging app? Here's our documentation on Android app config.
If you continue to experience issues, feel free to send over your APK file to integrations#branch.io and I'd be happy to investigate further for you.

Not able to retrieve data from firebase database in android

Database Structure:
appname/users/userID/personal/Name
The child "name" is upadated in the database but is returning as null.
mChildReference = FirebaseDatabase.getInstance().getReference().child("users").child(uid).child("personal"); //DatabaseReference
ValueEventListener postListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
User post = dataSnapshot.getValue(User.class);
Toast.makeText(MainActivity.this, "Name: "+post.uname+"dob: "+post.udob+"phno: "+post.phone_number+"email: "+post.uemail, Toast.LENGTH_LONG).show();
Log.e("RETRIEVED DATA", "Name: "+post.getUname()+"dob: "+post.getDob()+"phno: "+post.getPhone_number()+"email: "+post.getEmail());
Log.e("DEBUG",dataSnapshot.getKey());
fname.setText(post.getUname());
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
Log.e("DEBUG", "loadPost:onCancelled", databaseError.toException());
// [START_EXCLUDE]
Toast.makeText(MainActivity.this, "Failed to load post.",
Toast.LENGTH_SHORT).show();
// [END_EXCLUDE]
}
};
mChildReference.addValueEventListener(postListener);
mPostListener = postListener;
If the database is acting wierd, make sure you double-check your database rules. You can try to make them public for now. I find this useful when I am developing.
In the Firebase Console, click Database -> RULES
Set all permissions to public (Warning anyone
can read and write!)
// These rules give anyone, even people who are not users of your app,
// read and write access to your database
{
"rules": {
".read": true,
".write": true
}
}
Try the query on Android again and see if it works.

Firebase : Permission denied - while setValue()

I am trying to build a chat application using firebase.
The structure for message table :
message -
$message_id
- $message_push_id
- message {
sender : 3,
receiver : 58,
token : token_of_sender,
message : hi
....}
message_id here is generated using the sender and receiver ids "3_58"
I am using push to save messages into firebase.
{
"rules": {
".read": true,
"message":
{
"$messageid": {
"$messagepushid":
{
".read": true,
".write": "auth != null && !data.exists()",
".indexOn": ["token", "userid", "receiverid", "sent_time"],
".validate": "auth.token == newData.child('token').val() && newData.hasChildren(['token', 'userid', 'receiverid', 'text'])"
}
}
}
}
}
I have already generated token using custom token generator :
Firebase firebase = getFirebase();
Map<String, Object> authPayload = new HashMap<String, Object>();
authPayload.put("uid", user.getUserid());
authPayload.put("token", user.getToken());
TokenGenerator tokenGenerator = new TokenGenerator(Constants.FIREBASE_KEY);
TokenOptions tokenOptions = new TokenOptions();
tokenOptions.setAdmin(false);
final String firebaseToken = tokenGenerator.createToken(authPayload, tokenOptions);
firebase.authWithCustomToken(firebaseToken, new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
Log.d("Auth", "Success : " + authData.toString());
Log.d("Auth", "Token : " + firebaseToken);
SharedPrefs.setFirebaseUserToken(getActivity(), firebaseToken);
}
#Override
public void onAuthenticationError(FirebaseError
firebaseError) {
firebaseError.toException().printStackTrace();
}
});
I am trying to push a new message but I am getting error :
RepoOperation﹕ setValue at /message/3_58/-Jy2We4cqLjuQNF6Oyhs failed: FirebaseError: Permission denied
I am unable to figure out where I am going wrong.
This is the code to send chat :
mConversationReferenceFireBase = mFireBase.child("message").child(mConversationId);
Chat conversation = new Chat( mToken, mUserId, mReceiverId, message );
mConversationReferenceFireBase.push().setValue(conversation, new Firebase.CompletionListener() {
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
if (firebaseError != null) {
Log.e("Conversation", firebaseError.toString());
}
}
});
mConversationId = 3_58
The token here is generated for a user. We have a separate server to maintain the user accounts. The token is being used to upload/ download any files, the firebase is used as Chat Server.
With the rules set to .read = true and .write = true; everything works, however when I am attempting to have an authentication performed, it results in the error mentioned above. I've tried using the token from token generator, to check if I may possibly be using the wrong token.
I am following this example to generate token for firebase auth :
https://www.firebase.com/docs/web/guide/login/custom.html
Since storing a firebase secret key is bad in terms of security, what other alternative can be followed to generate a token for authentication?
I was too stuck on this point and here's what helped me.
First things first, there are two types of users who can access database from firebase
Authorized
Non-authorized
By default it is set to non-authorized but then they do not have any permissions neither read nor write, so initially if you try to perform any operation you get the permission denied error.
So basically one has to change the required permissions on the firebase console in-order to access the database.
Complete answer here
Check the rule defined in your firebase account and also the simulator options. Description is given below in a image.

Android: How to input values to Parse cloud code, eg beforesave

Inside a app, users will upload slot results with period name to the Parse Database. However, before upload, it would be much preferred if beforesave, checked whether the period ref is already there, if the same period ref is existing in the DB, the slot result would not be uploaded.
Cloud.beforesave
Parse.Cloud.beforeSave("check_duplicate", function(request, response)
{
var DB = Parse.Object.extend("Record_db");
var query = new Parse.Query(DB);
query.equalTo("period_ref", request.object.get("period_ref"));
query.first
({
success: function(object)
{
if (object)
{
response.error("A Period with this ref already exists.");
}
else
{
response.success();
}
},
error: function(error)
{
response.error("Could not validate uniqueness for this period ref object.");
}
});
});
Android code:
ParseCloud.callFunctionInBackground("check_duplicate", new HashMap<String, Object>(), new FunctionCallback<String>() {
public void done(String result, ParseException e)
{
if (e == null)
{
Utilities.custom_toast(CurrentResult.this, "cloud success" + result, "gone!", "short");
}
else
{
Utilities.custom_toast(CurrentResult.this, "cloud error" + e, "gone!", "short");
}
}
});
Question:
There is no clear example for such common situation. I would like to ask
for example, now the user would like to upload slot ref 001/2015 results. All info are already available at device, how could I pass this period reference 001/2015 to the cloud code for checking whether it is already existing in the Cloud DB uploading and saving to the Cloud DB?
Thanks a lot!
your first line of Android...
ParseCloud.callFunctionInBackground("check_duplicate", new HashMap(), new FunctionCallback() {
becomes
ParseCloud.callFunctionInBackground("check_duplicate",
new HashMap<String, String>{"period_ref":"001/2015"};,
new FunctionCallback<String>() {

Categories

Resources