Quickblox: how find out whether the user is online? - quickblox

Is there any way to find out whether the Quickblox user is online?
I'm using Quickblox iOS SDK.

There are 2 ways:
Using REST API - here is a guide http://quickblox.com/developers/SimpleSample-users-ios#Online.5COffline_status
Using Chat contact list http://quickblox.com/developers/SimpleSample-chat_users-ios#Contact_list

Swift 5 :
To get opponent user's Online Status And accurate Last Seen we have to add both users in each others contactList by using addUserToContactListRequest() API.
User A sends a request to become "friends" with user B. User B accepts the friend request. And now user A and B appear in each other's roster.
Step 1:
Check whether opponent user is already added in contacts or not
let isAvailable = QBChat.instance.contactList?.contacts?.filter {(contacts) -> Bool in
// self.dialog.recipientID is an opponent user's ID
return contacts.userID == self.dialog.recipientID ? true : false
}
If available in contacts check online status, if not available then send request to add in contacts.
if isAvailable!.count > 0 {
if isAvailable![0].isOnline {
//print("User Is Online")
} else {
//print("User Is Offline")
//Check Last Seen
self.fetchLastSeen(userId: self.dialog.recipientID)
}
} else {
QBChat.instance.addUser(toContactListRequest: UInt(self.dialog!.recipientID)) { (err) in
print("\(err)")
}
}
Step 2 :
implement QBChatDelegate methods.
Add contacts request
// This method will get called whenever you will receive any new add contact request
func chatDidReceiveContactAddRequest(fromUser userID: UInt) {
//Confirm add to contact list request.
QBChat.instance.confirmAddContactRequest(userID) { (error) in
}
}
Following method called in case when user's from contact list online status has been changed.
func chatDidReceiveContactItemActivity(_ userID: UInt, isOnline: Bool, status: String?) {
if userID == self.dialog.recipientID {
if isOnline {
print("User Is Online")
} else {
//print("User Is Offline")
//Check Last Seen
fetchLastSeen(userId: NSInteger(userID))
}
}
}
Step 3:
fetch the last seen of an user using this lastActivityForUser()
func fetchLastSeen(userId: NSInteger){
QBChat.instance.lastActivityForUser(withID: UInt(userId)) { (timeStamp, err) in
print(timeStamp)
// here we get total seconds, since how long user was inactive
// minus the seconds from current time
if err == nil {
let updatedTime = Calendar.current.date(byAdding: .second, value: -Int(timeStamp), to: Date())
guard let dateSent = updatedTime else {
return
}
var lastSeenStr = ""
if (Calendar.current.isDateInToday(updatedTime!)){
lastSeenStr = "Today"
} else if (Calendar.current.isDateInYesterday(updatedTime!)){
lastSeenStr = "Yesterday"
} else {
let dateFormat = DateFormatter()
dateFormat.dateFormat = "d-MMM"
lastSeenStr = dateFormat.string(from: updatedTime!)
}
let text = messageTimeDateFormatter.string(from: dateSent)
print("\(lastSeenStr + " " + text)") // e.g. 11-Sep 11:44 AM
}
}
}

Related

How to log empty Mono

Lets say I have the following lines
repository.findUser(name = "John Doe")
.map {
// User was found, continue processing
}
.switchIfEmpty(
// Just log that the user was not found
)
My non-best-practice-but-working approach currently is to just put the logging in another function and call it, like switchIfEmpty(userNotFound())
private fun userNotFound(): Mono<out Disposable> {
logger.info { "No user was found." }
return Mono.empty()
}
This works but I cannot imagine this is what I should be doing. How can I improve?
One way is to use the Mono.defer inside switchIfEmpty:
repository.findUser(name = "John Doe")
.switchIfEmpty(Mono.defer{ ... })
Alternatively, you could use doOnSuccess and check if Mono has completed without data(sample in Java):
repository.findUser(name = "John Doe")
.doOnSuccess(e -> {
if (e == null) {
log.info("No user was found.");
}
})

How to have Kotlin "Listen" when a function finish executing Successfully

This is my first time using Kotlin, I have to write a simple command-line application where it takes a list of user input strings. Valid inputs are only "Apple" or "Orange" and calculate the price (which is 60 cents and 25 cents respectively). I'm having some trouble with the 3rd requirement
"Build a service that listens for when orders are complete and sends a notification to the customer regarding its status and estimated delivery time. The Mail service subscribes to events from the Orders service and publishes the appropriate event that the customer (you) is able to read from the terminal"
this is what I have done so far
MainApp.tk
import java.util.Scanner
import kotlin.system.exitProcess;
import app.Checkout;
var shopRunning = true;
var applecount = 0;
fun main(args: Array<String>) {
while (shopRunning) {
println("Welcome to Express Store");
println("1. Checkout");
println("2. exit");
var userOption = 0;
//request the user to eneter an option
//if user eneter a options that is not valid it will keep looping til option that is enterd is accepted;
var userSeletedOption = false;
val inputScanner = Scanner(System.`in`);
while (!userSeletedOption) {
print("Select an Option: ");
userOption = inputScanner.nextInt();
//if input entered by the user is not accepted and invaliud message is printed and is promted to enter an option again.
if (userOption != 1 && userOption != 2) {
println("Invalid input detected!");
} else {
userSeletedOption = true;
}
}
if (userOption == 1) {
val checkout = Checkout();
println("We currently have apples and oranges in Stock.")
var list: MutableList<String> = ArrayList();
println(list.size);
var doneAddingToCart = false;
while(!doneAddingToCart){
print("enter name of item to be enter or exit to finish adding to the cart: ")
var item = inputScanner.next();
if(item.equals("exit")){
doneAddingToCart=true;
}
else{
list.add(item);
}
}
if(checkout.verify(list)){ //checks if list has any item that is not an apple or orange
println("Thank you for your Pruchse");
val cost = checkout.Chasher(list)
println("You bought: "+ list.toString());
print("your total is: "+ cost);//returns the total cost
exitProcess(1);//exits from the application
}
} else if (userOption == 2) {
print("Have a great day.");
exitProcess(1);
}
}
}
CheckOut.tk
class Checkout {
//checks if the user entered any invaild items
public fun verify (cart: MutableList<String>) : Boolean{
for(item in cart){
if(!item.equals("Apple") && !item.equals("Orange")){
return false;
}
}
return true;
}
public fun Chasher (cart: MutableList<String>) : Double{
var total = 0.0;
var orangecount = 0;//step 2 offers
var applecount = 0;//step 2 offers
for(item in cart){//step 1 function
if(item.equals("Apple") || item.equals("apple")){
applecount+=1;
total= total + 0.6;
}
if(item.equals("Orange") || item.equals("orange")){
orangecount +=1;
total=total +0.25;
}
}
if(orangecount ==3){//buy three for the price of 2.step 2
println("You qaulidified for our buy 3 oragnes for the price of 2 offer")
total -=0.25;
}
if(applecount ==1){//buy one aple get 1 free. step 2
println("You buy 1 apple get one free")
cart.add("Apple");
}
return total;
}
}
I don't need to send an email just send a message to the command line. Currently, I'm just printing messages (just to see if what I currently have even works). Yeah, I know there many spelling errors, english and writing was never my strongest subject
I can only provide three hints that might help you:
If you exit your program using System.exit, use 0 if the run did not have any problem. (Excerpt from JavaDoc: "The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.")
For checking equality, simply use == which corresponds to equals in Java. In your special case however, you can use item.equals("apple", ignoreCase=true) or simply item.equals("apple", true).
I'm not sure what the author of your task exactly expects as a solution.
In can imagine you are expected to use lambdas.
An example: Your could refactor your Checkout class like that:
class Checkout {
/**
* Checks if the given [cart] contains only apples and oranges,
* and calls [onSuccess].
* If also other articles are contained, [onSuccess] is not called.
*/
fun verify(cart: List<String>, onSuccess: (List<String>) -> Unit): Unit {
for (item in cart) {
if (!item.equals("apple", true) && !item.equals("Orange", true)) {
return
}
}
onSuccess(cart)
}
}
And then call
val cart = listOf("Orange", "Apple", "apple", "orange")
Checkout().verify(cart, { cart: List<String> ->
println("Thanks you for your purchase: $cart")
})
or even shorter (curly brackets are outside of parenthesis)
Checkout().verify(cart) { cart: List<String> ->
println("Thanks you for your purchase: $cart")
}
What I did here was to extract what is executed if your validation succeeds:
For that, I used a lambda function that accepts a list of articles/strings (List<String>) and returns something I ignore/don't care about -> Unit.
The advantage of that approach is that callers of your verify method can decide what to do on success at their liking because they can pass a lambda function around like any other variable. Here:
val cart = listOf("Orange", "Apple", "apple", "orange")
val onSuccess = { cart: List<String> ->
println("Thanks you for your purchase: $cart")
}
Checkout().verify(cart, onSuccess)
You could also extend Checkout to allow an observer to register.
I deliberately kept the code very simple. Normally you would allow multiple observers to register, only expose what clients are supposed to see and hide the rest, etc.
class Checkout(
val onSuccess : (List<String>) -> Unit
) {
fun verify(cart: List<String>): Unit {
for (item in cart) {
if (!item.equals("apple", true) && !item.equals("Orange", true)) {
return
}
}
onSuccess(cart)
}
}
val checkout = Checkout({ cart: List<String> ->
println("Thanks you for your purchase: $cart")
})
and then
val cart = listOf("Orange", "Apple", "apple", "orange")
checkout.verify(cart)
Be sure to check out https://play.kotlinlang.org/byExample/04_functional/01_Higher-Order%20Functions to learn more about lambda / higher-order functions.

How to dynamically choose which authentication method is used in Ktor?

I implemented google sign-in in my application like so:
fun Application.module(testing: Boolean = false) {
install(CallLogging)
install(ContentNegotiation) {
gson {
setPrettyPrinting()
}
}
val jwtIssuer = environment.config.property("jwt.domain").getString()
val jwtAudience = environment.config.property("jwt.audience").getString()
val jwtRealm = environment.config.property("jwt.realm").getString()
val jwkProvider = JwkProviderBuilder(URL("https://www.googleapis.com/oauth2/v3/certs"))
.cached(10, 24, TimeUnit.HOURS)
.rateLimited(10, 1, TimeUnit.MINUTES)
.build()
install(Authentication) {
jwt {
verifier(jwkProvider) {
withIssuer(jwtIssuer)
withAudience(jwtAudience)
}
realm = jwtRealm
validate { credentials ->
if (credentials.payload.audience.contains(jwtAudience))
JWTPrincipal(credentials.payload)
else
null
}
}
}
routing {
authenticate {
post("/token-sign-in") {
val payload = call.principal<JWTPrincipal>()?.payload ?: error("JWTPrincipal not found")
call.respond(
UserWire(
id = payload.subject,
email = payload.getClaim("email").asString(),
name = payload.getClaim("name").asString(),
profilePictureUrl = payload.getClaim("picture").asString()
)
)
}
}
}
}
I want to authenticate the user every single time they access one of the routes, but I want to have both google and firebase-auth login as an option. The thing is that they require different methods to check the authenticity of the given token, hence I need two authentication methods.
I was thinking of including an "AuthenticationProvider: "Google|Firebase"" in the header of the call, and according to its value, I would decide which authentication method should be called.
So something like this:
fun Application.module(testing: Boolean = false) {
install(Authentication) {
jwt("google") {
// verify google sign in token
}
jwt("firebase") {
// verify firebase token
}
firebaseOrGoogle("firebaseOrGoogle") {
// check header value for auth provider
// verify token with either "firebase" or "google" auth methods
}
}
routing {
authenticate("firebaseOrGoogle") {
post("/token-sign-in") {
// ...
}
get("/transactions") {
// ...
}
}
}
}
Is this at all possible?
If this is possible please could you provide some code as to how to dynamically decide which authentication method should be called?
As an alternative solution, you can configure an authentication feature to try proving the identity of a user by both methods. The first successful check wins. To do that just pass those two configuration names to the authenticate method:
routing {
authenticate("google", "firebase") {
post("/token-sign-in") {
// ...
}
get("/transactions") {
// ...
}
}
}
The order of arguments determines what check comes first.

app and app extension fetching contacts from contact book

Im trying to integrate Siri. For this I turned on AppGrouping for my app. I was trying to use user defaults to save contacts. But it says: "Attempt to set a non-property-list object". What I'm doing wrong?
class func allContacts() {
let store = CNContactStore();
let request = CNContactFetchRequest(keysToFetch: [CNContactGivenNameKey as CNKeyDescriptor,CNContactPhoneNumbersKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor,CNContactImageDataKey as CNKeyDescriptor,CNContactThumbnailImageDataKey as CNKeyDescriptor,CNContactNicknameKey as CNKeyDescriptor])
var localContacts = [INContact]()
do{
try store.enumerateContacts(with: request, usingBlock: { (contact, status) -> Void in
let newContact = INContact(name: contact.givenName, phone: contact.phoneNumbers)
localContacts.append(newContact)
})
}
catch let error as NSError! {
print ("Error: \(error.domain)")
}
guard let shared = UserDefaults.init(suiteName: "group.mygroup.com") else {
return
}
shared.setValue(localContacts, forKey: "Contacts")
shared.synchronize()
}
How to get list of contacts of app for IntentHandler and fetch it?

iOS - my app keeps asking for sandboxed user to login

I created a sandboxed user. Signed out of app store on my device, and used my test user to make a test purchase. All good.
Now I signed back into my real account. Every time I open the app, it asks for my test user's credentials immediately.
I tried deleting my test user. I tried deleting the app. I tried signing out of app store. It's STILL asking for this test user's credentials on every app launch on my device. How do I start fresh?
here is my code, although I'm not sure it's really related to my issue
override func viewDidLoad() {
// storekit delegation
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
self.getProductInfo()
}
func getProductInfo(){
if SKPaymentQueue.canMakePayments() {
let request = SKProductsRequest(productIdentifiers: NSSet(object: self.productID))
request.delegate = self
request.start()
}
// else {
// please enable in app purchases
// }
}
Delegate methods
func productsRequest(request: SKProductsRequest!, didReceiveResponse response: SKProductsResponse!) {
var products = response.products
if products.count != 0 {
self.product = products[0] as? SKProduct
}
}
func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue!) {
if queue.transactions.count != 0 {
if let purchase = queue.transactions[0] as? SKPaymentTransaction {
if purchase.payment.productIdentifier == self.productID {
println("you bought it already")
}
}
}
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
for transaction in transactions as [SKPaymentTransaction] {
switch transaction.transactionState {
case SKPaymentTransactionState.Purchased:
// self.unlockFeature()
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
case SKPaymentTransactionState.Failed:
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
default:
break
}
}
}