Laravel - Check for new message inside conversation - laravel

I created application in Laravel where users can communicate using Facebook-like messages. Now I have problem when I check for new messages. I created function which needs to query all conversations and all messages inside those conversations to find new (unopened) messages.
So I'm asking if there is different way for achiving this - without stressing too much the server with all those queries.
This is my function:
function newMessage(){
if(Auth::check()){
$conversations = User::find(Auth::user()->id)->conversations;
$new = false;
foreach ($conversations as $key => $value) {
if(count(Conversation::find($value->id)->messages()->where("user_id", "!=", Auth::user()->id)->where("opened", "=", 0)->get()) > 0){
$new = true;
}
}
return $new;
}else{
return false;
}
}
Relationship between conversation and message is one to many.
Conversation table consists only of id and message table has id and opened (I'm giving you only relevant columns).

This is how I solved it:
created opened column in conversation_user table
when user opens a message opened column updates to 1
when user sends message, opened column updates to 0 for every user in that conversation except for the user who sends the message
And I wrote this function which will check if user has new messages (inside User model):
public function hasUnread(){
return (bool)$this->conversations()->whereOpened(0)->count();
}

Related

CodeIgniter delete query does not work in foreach loop?

I have the following code to remove user accounts that have not verified their email address within one week. The query works as I expect, but the delete function only deletes the first record, and I cant figure out why. The print_r generates the full results as I expect, but the delete function is somehow ignored. Any ideas on how to make it so it deletes all relevant records?
public function databaseupdate () //REMOVES ALL UNVERIFIED EMAIL ACCOUNTS OLDER THAN 1 WEEK - REQUIRES MANUAL BUTTON PRESS BY ADMIN
{
$verified = 'no';
$tables = array('register', 'profiles', 'profilesmember');
$deletedate = date('Y-m-d', strtotime('-7 days'));
$this->db->select('email');
$this->db->where('is_email_verified', $verified);
$this->db->where("DATE_FORMAT(created_date,'%Y-%m-%d') <='$deletedate'");
$this->db->from('register');
$query = $this->db->get();
foreach($query->result() as $row)
{
$email = $row->email;
$this->db->where('email', $email);
$this->db->delete($tables);
// print_r($email);
}
}
You are looping on the WHERE statement which will work for the first instance as you have observed, but subsequent ones, it will not, as you are adding WHERE statements like
Loop 1: WHERE email = email1
Loop 2: WHERE email = email1 AND email = email2
Loop n: WHERE email = email1 AND email = email2 AND ..... email = emailn
and it will just keep on building. Its the very same behaviour as you have used in your query above with the multiple WHERE statements.
So you need to perform a reset on the query.
$this->db->reset_query();
So your loop might look like...
foreach($query->result() as $row)
{
$this->db->where('email', $row->email);
$this->db->delete($tables);
$this->db->reset_query();
}
Then you will get what you are expecting.
Loop 1: WHERE email = email1
Loop 2: WHERE email = email2
Loop n: WHERE email = emailn
While the above "Works" you should be considering what is you are trying to achieve here...
You want to create a list of Emails that you want to delete from a number of tables.
Just NOTE: We have no idea on how these tables are related etc so just be aware of the possibility of leaving "orphan" records. There are many ways to deal with this but its way outside this discussion.
An Option is to check you have some results, build the where query then perform the delete. So it's only "1 Trip" to the Database" and not "n Trips".
// Did we get any results to delete?
if($query AND $query->num_rows()) {
foreach($query->result() as $row)
{
// Build the WHERE Statement
$this->db->or_where('email', $row->email);
}
$this->db->delete($tables); // Execute the Delete.
}
So it's important to understand the various ways to do this... I.E there are others. But for this case, it should be fine (famous last words).
Further to TimBrownlaw's answer using or_where also works:
foreach($query->result() as $row)
{
$this->db->or_where('email', $row->email);
$this->db->delete($tables);
}

How to handle data before delete from model in Laravel?

I have the following method:
public function destroy($id)
{
$id = \JWTAuth::parseToken()->authenticate();
$offer = Offer::findOrFail($id);
$offer->delete();
return response()->json(["offer" => $offer]);
}
How handle data before deleting? I need to check if user has permit to delete data or not
When you use the authenticate() method, the user model is retrieved so it means the id you have is not an id but a User. Have you checked the documentation of JWT Because first and foremost you have to retrieve the user and this is sufficient:
$user = \JWTAuth::parseToken()->authenticate();
Then if you have a field for example in your users table to tell if the user have the right say admin which can be 1 or 0 then you can do the following:
if($user->admin == 1)
{
$offer = Offer::findOrFail(1); //say id
$offer->delete();
return response()->json(["offer" => $offer]);
}
return response()->json(['error' => 'you dont have the right to delete this'], 403);
Just a little scratch on the idea, but my best advice is to do some searches on how JWT is implemented, I am pretty sure you will find tons of them online.
I would recommend using the Model's delete event:
https://github.com/laravel/framework/blob/5.2/src/Illuminate/Database/Eloquent/Model.php#L1122
and handle it.
This will guarantee that if you use the delete method on a model, you always check permissions.

symfony 3 time when log in and log out

I'm pretty much new in symfony 3, so how I could get time when user log in and log out.. I know i should create entity for time.. that entity would have id,userID startTime, endTime.. and user should have a connection(many to many, that lot of user could have lot of log in.. ) with this entity.... I'd like to store in database this information. I tried to search on google but I found nothing in common.
I'd like to activate time startTime when this button is pressed
Sign
in
and code in controller
#Route("/login", name="authentication_login")
public function loginActionAction(Request $request)
{
$authenticationUtils = $this->get('security.authentication_utils');
// get the login error if there is one
$error = $authenticationUtils->getLastAuthenticationError();
// last username entered by the user
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('AppBundle:uzduotis:login.html.twig', array(
'last_username' => $lastUsername,
'error' => $error,
));
}
then for endTime
/**
* #Route("/logout", name="logout")
* #Method({"GET"})
*/
public function logoutAction(Request $request)
{
$session = $this->$request->getSession();
$session = $this->get('session')->clear();
return $this->render('AppBundle:uzduotis:login.html.twig');
}
For this answer I assume you store the users in the database. If not, please show how you do it.
First of all please have a look at the doctrine documentation on how to connect entities to each other. In your case this should help:
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#one-to-many-bidirectional
There's also a pretty good tutorial on this subject in the Symfony documentation: http://symfony.com/doc/current/doctrine/associations.html
In the controller you can fetch the currently logged in user by executing $user = $this->get('security.token_storage')->getToken()->getUser();. That will return the database entity of the user that you can modify immediately. E.g. by adding a new record to the time table (example code):
$time = new TimeLog();
$time->setUser($user);
$time->setType('login');
$time->setTimestamp(time());
In case saving does not work, try with the persist and flush methods of $this->get('doctrine')->getManager(). There's lots of documentation about this, too.

Codeigniter securing certain pages based on user account

I am developing a system whereby a user is a member of a Client account. There are 5 or 6 clients, and each client has a number of users. When a user logs in, the site is styled to the client they are a member of.
I have a function "view_campaign":
function view_campaign($campaignID = FALSE){
$this->load->model('client_model');
$this->load->model('campaign_model');
$data['main_content'] = 'campaign_overview';
$this->load->view('includes/template', $data);
}
So in the URL for example we have .../campaign/view_campaign/21 (for example). This will mean that the user gets to their campaign which has an ID of 21.
But how can I make it so it's secure i.e. users that are members of another client cant view the campaign? They could just change the URL and view campaigns related to other clients...
Thanks
Quite a broad question, I'm not sure what your database structure is but you want to do something like...
When the user first logs in you want to save their user ID and their client ID in a session. Then you want to have a function in your campaign model that gets the client ID a campaign belongs to.
Your view_campaign function would look something like
function view_campaign($campaignID = FALSE) {
$this->load->model('client_model');
$this->load->model('campaign_model');
//Get the user ID and client ID from a session or something
$userId = $this->session->userdata('userId');
$clientId = $this->session->userdata('clientId');
//Call a function in your model to see if the user belongs to the client
$campaignClientId = $this->campaign_model->getClient($campaignID )
//If the client ID the campaign belongs to matches the client ID the user
//belongs to then they can view it
if($campaignClientId === $clientId ) {
$data['main_content'] = 'campaign_overview';
$this->load->view('includes/template', $data);
} else {
//Redirect to another page
}
}

sending email to all newsletter members with codeigniter

I want to send an email using codeigniter library to my newsletter members and I want to mention each members' Email address in email's content. For doing that, I used foreach loop to send the email one by one. The problem is that the code sends email to just one member ( the first member ) of my newsletter. I've checked my code which gets members from the database and it printed out all the members.
This is my model:
function send_news()
{
$subscribers = $this->get_subscriber_data();
foreach($subscribers as $subscriber)
{
$this->load->helper('typography');
//Format email content using an HTML file
$data['news_Title'] = $this->input->post('news_Title');
$HTML_Message = $this->load->view('admin/includes/newsletter_html_format', $data, true);
$config['mailtype'] = 'html';
$this->email->initialize($config);
$this->email->from('newsletter#site.com', 'newsletter of site.com');
$this->email->to($subscriber->subscriber_Email);
$this->email->subject('newsletter of site.com');
$this->email->message($HTML_Message);
return $this->email->send();
}
}
and this is how I'm getting subscribers list:
function get_subscriber_data($options = array())
{
$query = $this->db->get('mg_newsletter');
if(isset($options['subscriber_Id']))
return $query->row(0);
return $query->result();
}
when I try to echo $subscriber->subscriber_Email it prints all the emails in the database one after another. but it does not send email to all of them. What am I doing wrong?!
use
$this->email->clear()
As codeignitor says:
Initializes all the email variables to an empty state. This function is intended for use if you run the email sending function in a loop, permitting the data to be reset between cycles.
foreach ($list as $name => $address)
{
$this->email->clear();
$this->email->to($address);
$this->email->from('your#example.com');
$this->email->subject('Here is your info '.$name);
$this->email->message('Hi '.$name.' Here is the info you requested.');
$this->email->send();
}
If you set the parameter to TRUE any attachments will be cleared as well. Then let us know
You are "return" -ing inside your loop, which exits the function.
Just send
You can keep the loading helper file and email configuration outside the loop and then remove the return from for loop, it will send to all subscribers one by one and then after loop finishes you can do the return statement.

Resources