One to one chat in socket io - socket.io

Need help with socketio one to one chat.
I have read tons of example stating to create a room for private chat.
The example one I always get will be something like this :
io.on('connection', socket => {
//Get the chatID of the user and join in a room of the same chatID
chatID = socket.handshake.query.chatID
socket.join(chatID)
//Leave the room if the user closes the socket
socket.on('disconnect', () => {
socket.leave(chatID)
})
//Send message to only a particular user
socket.on('send_message', message => {
receiverChatID = message.receiverChatID
senderChatID = message.senderChatID
content = message.content
//Send message to only that particular room
socket.in(receiverChatID).emit('receive_message', {
'content': content,
'senderChatID': senderChatID,
'receiverChatID':receiverChatID,
})
})
});
But I can't get my head around: as in this example for the room "receiverChatID", all user who are currently sending message to the same receiver [say user2] will receive a broadcast of the messages other user are sending.
For example user 1 and user 2 are having private chat conversation. The chat room id is "user2".
Now user3 sends message to user 2, again the room name will be "user2" and hence when a broadcast will be done, both user 3 and user 1 will receive messages , even though they should be private individually.
One way will be to create a unique chat-room-id between two users, and maintain in it some data store.If that is the way to do it, then how to create unique chat room id, specifically, when user join and leave and re-join save room.
And query this unqique room for two users, whenever they join in ?
Say I create a map : {roomid1: MD5["user1","user2"]}.
Now how do you decide the order of user1 and user 2 [alphabetical I guess], so for two pairs of users one unique room id is created ?
How do you solve this problems for one to one chat ?

Related

Private message with laravel

I am building a simple private chat app with laravel and vue js.
I have a messages table with a column : id/sender_id/receiver_id and body
my main problem is fetching the users from the messages table. so if sender_id 1 has sent the message to receiver_id 2 then In the sender dashboard, I want to display the NAME of the receiver with receiver id 2 and on clicking the name I want to fetch conversation between these two users.
similarly, in the receiver dashboard, I want to show the list of all users who have sent a message.
so in short, as a logged-in user, I should see the name of users to whom I have sent a message and from whom I got the messages, and when clicking those names I will able to see all the conversations.
Message.php
class Message extends Model
{
use HasFactory;
public function user(){
return $this->belongsTo(User::class);
}
}
currently, I am doing like this
Route::get('/messages','MessageController#index');
public function index()
{
$messages = Message::with('user')
->groupBy('sender_id')
->where('receiver_id',auth()->user()->id)
->orWhere('sender_id',auth()->user()->id)
->get();
}
and my vue is like this
<li v-for="(person,index) in users" :key="index">
{{person.user.name}}{{person.user_id}}
</li>
export default{
data(){
return{
users:[],
messages:[],
}
},
mounted(){
axios.get('/api/users').then((response)=>{
this.users = response.data
})
}
//....
}
my problem is: if I (let's say john )sent a message to David(receiver), I see John name on David dashboard which is correct so on clicking John name I can fetch all the conversation between John and David However, On john's dashboard(message sender to David) I see John's name, but I need here David's name.
so on the sender dashboard, I need the receiver name and on the receiver dashboard, I need sender name.
I think this probably related to the query. please help me. Thanks

Create indirect relationships and return the sum of two relationships

I have a program to share services between people. Basically I am facing a problem trying to get the conversations between users. Here is the idea:
My program allows users to offer services to other users, but also to acquire services from other users. Each user can register an unlimited number of services.
When a user finds a service that he/she wants to get, he creates a deal and starts a conversation with the counterpart.
The structure of my tables is the following (I am only including the relationship columns):
Users table
id // This is the user identifier
Services table
id // This is the service identifier
user_id // This is the identifier of the user who created the service
Deals table
id // This is the deal identifier
user_id // This is the identifier of the user acquiring the service
service_id // This is the identifier of the service being acquired in this deal
Conversations table
id // This is the identifier of the conversation
deal_id // This is the identifier of the deal that the conversation belongs to
Here is my problem:
I want to be able to retrieve the conversations for each user, both as applicant and as a seller.
I created this relationship (in User.php) for conversations in which the user is acquiring the service:
public function conversationsApplicant(){
return $this->hasManyThrough( Conversations::class, Deal::class );
}
I would like to create also the conversationsSeller() function
public function conversationsSeller(){
return $this->????;
}
I am guessing I should add some kind of relationship between a Conversation and a Service in Service.php. It would be something like $this->services()->with( 'deals' )->with( 'conversations' );
The final goal would be to have a method that returns both relationships in one $user->conversations()->get().
public function conversations(){
return $this->conversationsApplicant() + $this->conversationsSeller();
}
To retrieve the relationship I was thinking that maybe there is a workaround using a SQL query, but I am not sure if that will return the relationship as I need it. Here is the query that I need to perform:
SELECT
conversations.*
FROM
mydb.conversations, mydb.services, mydb.users, mydb.deals
WHERE
users.id = services.user_id AND
services.id = deals.service_id AND
deals.id = conversations.deal_id AND
users.id = $user->id;
Here is how you implement merged relationship simply
public function getCombinedChats($value)
{
// There two calls return collections
// as defined in relations.
$Applicant= $this->conversationsApplicant;
$Seller= $this->conversationsSeller;
// Merge collections and return single collection.
return $Applicant->merge($Seller);
}

Send 2 different types of mails using mailchimp

I have a set of internal users for my project. Admin can activate/deactivate them. I want to send them a mail saying "your account has been deactivated" when their account is deactivated by admin. Similarly they should receive a mail saying "your account has been activated" when admin activates their account. How can I do this?
I am trying by creating 2 separate lists in mailchimp and two separate campaigns. but when I'm writing mailchimps credentials in my development.js with 2 separate list ids and then trying to get it in my javascript file,it is getting undefined (checked by console.log)..
Is there a way to do it by just single campaign/list?
Here's my development.js code of mailchimp credentials:
mailchimp: {
api_key: "***************-***",
list_id1: "*********", //internal users
list_id2: "*********" //internal deactivated users
},
my user.helper.js
const config = require('../../config/environment');
const Mailchimp = require('mailchimp-api-3');
const mailchimp = new Mailchimp(config.mailchimp.api_key);
exports.addToDeactivatedList = function (email, name) {
console.log(mailchimp.list_id1);
mailchimp.members.create(config.mailchimp.list_id1, {
email_address: email,
merge_fields: {
FNAME: name
},
status: 'subscribed'
}).then(user => { }).catch(e => {
console.log("deactivate list me add ho gya");
})
}
exports.addToActivatedList = function (email, name) {
console.log(mailchimp.list_id2);
mailchimp.members.create(config.mailchimp.list_id2, {
email_address: email,
merge_fields: {
FNAME: name
},
status: 'subscribed'
}).then(user => { }).catch(e => {
console.log("activate list me add ho gya");
})
}
and my user.controller.js (selective part only)
var helper = require('./user.helper');
.
.
if(req.body.status != user.status){
(req.body.status == "active") ? helper.addToActivatedList(user.email, user.name) : helper.addToDeactivatedList(user.email, user.name);
}
All the help will be appreciated. THANKS
I'd try to put everyone in the same list, and then create segments based on that list. After that, create a campaign based on that segment.
You could for instance create a custom list attribute that records wether or not an account is activated and create a segment based on that attribute. The campaign should then be based on that segment.
Perhaps also record the date an account has been activated or deactivated by the admin in another custom attribute and use that to check if a user already had an activation/deactivation mail.
MailChimp offers a feature for situations like this called automations. Automations allow you to send individual emails to subscribers when an event is triggered. So instead of creating separate campaigns every time a user is activated or deactivated, you can use just two automations and a single list.
Whether a user is active or not can be tracked with list merge fields. To do this, you'll need to add a new text merge field to your list. Let's name the field label 'Active'. Uncheck the 'Visible' checkbox so the user can't see it, and name your merge field something like 'ACTIVE'. You can use values like yes/no or true/false to identify the users by their active status.
Next, create your automations, one for activated users and one for deactivated users. You can set a trigger to send the email when a list field value is changed. So just make each of your two automations send the emails when the 'Active' list field values change to either 'yes' or 'no'.
Then all you need to do with the API is subscribe users to a single list whenever their accounts are activated or deactivated. Just make sure the new 'ACTIVE' merge field is set to 'yes' or 'no' when you do this, and any addresses already subscribed will be updated with the new value. So your mailchimp.members.create() would look something like this, based on the example from here:
mailchimp.members.create(<list_id>, {
email_address: <user_email>,
merge_fields: {
FNAME: name,
ACTIVE: 'yes' //Or 'no' if being used for deactivated users
},
status: 'subscribed'
})

Laravel Cashier list all user invoices

How to display all user invoices for referencing in the admin section of the application.
I can get a user invoices by
$userinvoices = $user->invoices();
Or I can get all invoice by stripe API:
$invoices = \Stripe\Invoice::all(array("limit" => 30));
in the second case, I can't get the details of the user the invoice belongs to.
Or is there any way to save invoice data to database on every creation of the invoice in stripe.
Your first option is the better way to go since you have all the information on the invoice and also the user info on the object.
If you want, you can go to your stripe dashboard -> Your account -> account settings -> webhooks -> add endpoint -> select events and select the invoiceitem.created event. setup your endpoint in the application and do whatever you need with it.
Example:
public function invoiceCreated(Request $request){
$payload = $request->all();
if($payload['type'] == 'invoiceitem.created'){
// do whatever you want with the $payload["data"]...
}
}
Good Luck :)

Get all contacts from exchange server

I want to get all users from Exchange server, I don't want to get user's contacts. In fact, I want to get all AD users as Active Directory which we can't connect to.
mExchangeService.ImpersonatedUserId = new ImpersonatedUserId
{
Id = "jack#aa.com",
IdType = ConnectingIdType.SmtpAddress
};
var contacts = _mExchangeService.FindItems(new FolderId(WellKnownFolderName.Contacts),new ItemView(1000));
I can above code to get user's contact, but that's not I want, I want use a service account to get all Exchange web service users.
You can sort of use EWS for retrieving your directory users using ExhangeService.ResolveName. The problem is that EWS will return no more than 100 users and there is no way to change it or to do any paging. So if you are in a larger company you can't really do it using EWS.
The code:
var nameResolutionCollection = service.ResolveName("SMTP:",
ResolveNameSearchLocation.DirectoryOnly, true);
foreach (var c in nameResolutionCollection)
{
Console.WriteLine(c.Mailbox.Address);
}
Console.WriteLine(nameResolutionCollection.Count()); // Maximum 100 users.

Resources