Laravel PDF generation with Graph and send it with Email - laravel

I tried to find it on StackOverflow and also tried to google it, but could not find any relevant answer.
I want to send monthly reports to the user of Laravel application with a PDF that contain a graph/chart.
This is what that is already done
Created a route, lets say
Route::get('/print/', 'PrintController#report');
In printController created a report function that is getting all the necessary data from the DB and returning a view with user data
return view::make('monthly_report', $user_data);
In monthly_report view, get all the user data, show the view and create a chart with the data. The chart is created with Charts.js. it is in a canvas.
Send the generated chart as image to the server with Ajax. For example
var canvas = document.getElementById("myChart"), // Get your canvas
imgdata = canvas.toDataURL();
file_name = "<?php echo $chart_file_name; ?>"; //created with userId and date
//send it to server
$.ajax({
method: "POST",
url: "save",
data: {
data: imgdata,
file_name: file_name,
_token: token,
}
});
Created a save route
Route::post('print/save', 'PrintController#saveChart');
In print controller, saveChart function, save the chart
$data = base64_decode($data);
//save chart on server
file_put_contents("Charts/".$fileName, $data);
Then create a PDF report by using another view monthly_report2, that is also in saveChart function. The view monthly_report2 does not use any JavaScript and use the chart image that was generated by monthly_report, in number 6.
$pdf = \PDF::loadView('monthly_report2', $cll_data);
file_put_contents("reports/".$pdf_name, $pdf->output());
It save the generated PDF on server. So far so good.
To send these PDF reports to the users by e-mail, I will created a schedule/crone job that will be run on a specific date, monthly and will send the e-mails with PDF reports as attachments.
I skip some details for clarity, please ask, if you need more information.
Thank you for reading so far, now I have two questions
The way I am doing is good or it can be improve?
We want all this process automatically (generating reports and sending by email). To generate the PDF's, monthly_report view must be loaded? so that it generate the Chart and send it to the server. Can we schedule it also, so that it generate the pdf reports automatically?, If no, is there any other way to do it?

Kind of a big question, but I'll try to answer
I think it's good. I'm not a big fan of using JavaScript to create charts, but that's me. You obviously know what you're doing and PDF generation is in my experience a "If it works, please don't break it" functionality.
I think this might be more difficult. Since you're using JavaScript to create charts, you need some kind of engine (NodeJS comes to mind) to parse the JavaScript and actually create your charts without opening a browser and doing it manually. (This is why I don't like using JavaScript to create charts). You could take a look at tutorials like this one to get an idea of how to render your charts serverside.
After that, you can take a look at the Laravel task scheduler (provided you're on Laravel 5, a community package exists for Laravel 4). You can schedule existing and custom-made commands to be executed. In pseudo-code, a PDF generation command could look like this:
public function createAndSendCharts() {
// 1. Get necessary user data
// 2. Create your charts
// 3. Save your charts
// 4. Create email with charts
// 5. Send your email
}
You could then add that function to your Task Scheduler
$schedule->command('send:charts')
->monthly();
Hope this was of some help. All in all, you're doing fine, but the choice for ChartJS has some consequences if you want to automate the whole process. Nothing really special, tons of tutorials exist for this situation :)

Related

Retrieve specific value from api response in google sheets

Sorting out some of my trading cards into google sheets. I would like retrieve the average price of the card using yugiohprices api (https://yugiohprices.docs.apiary.io/#reference/checking-card-prices/check-price-for-cards-print-tag/check-price-for-card's-print-tag?console=1)
I can link the cell to retrieve the cards data. But I would only like to get the average price value
sample sheet
NAME, SET, AVERAGE_PRICE
JINZO PSV-000 =IMPORTDATA(CONCATENATE("https://yugiohprices.com/api/price_for_print_tag/",B2))
https://yugiohprices.com/api/price_for_print_tag/PSV-000
{"status":"success","data":{"name":"Blue-Eyes White Dragon","card_type":"monster","property":null,"family":"light","type":"Dragon / Normal","price_data":{"name":"Legend of Blue Eyes White Dragon","print_tag":"LOB-001","rarity":"Ultra Rare","price_data":{"status":"success","data":{"listings":[],"prices":{"high":125000.0,"low":22.22,"average":81.48,"shift":-0.281354736285059,"shift_3":-0.275475724702116,"shift_7":-0.302755433852473,"shift_21":-0.345173993409949,"shift_30":-0.302874743326489,"shift_90":0.0978172999191593,"shift_180":0.886984715145901,"shift_365":-0.525699982536818,"updated_at":"2022-04-11 13:55:38 -0600"}}}}}}
When you want to retrieve the value from JSON data, I thought that a custom function created by Google Apps Script might be useful.
Sample script:
Please copy and paste the following script to the script editor of Spreadsheet. And save the script. When you use this, please put =SAMPLE("https://yugiohprices.com/api/price_for_print_tag/PSV-000") to a cell. By this, the value of obj.data.price_data.price_data.data.prices.average is retrieved.
function SAMPLE(url) {
const res = UrlFetchApp.fetch(url);
const obj = JSON.parse(res.getContentText());
return obj.data.price_data.price_data.data.prices.average;
}
Testing:
When this script is run using =SAMPLE("https://yugiohprices.com/api/price_for_print_tag/PSV-000"), the following result is obtained.
Note:
If the above custom function doesn't work, please reopen Spreadsheet and test it again.
References:
Custom Functions in Google Sheets

How do I hide posts with a specific hashtag in Yammer?

I want to hide posts in the feed that have a #joined hashtag. I tried to create a GreaseMonkey script with jQuery in the past, but it couldn't detect any posts that have the #joined text.
Am I using the wrong library? A starting point, or an existing library/plug-in would be helpful.
OFF-TOPIC: At the moment, Yammer does not have any feature to hide posts with a specific hashtag, although it has a feature to follow a hashtag.
I know that this is a pretty old question but I too was trying to create a Chrome based Add-on that hides these #joined posts (or any post with a specific hashtag). I came across this blog https://you.stonybrook.edu/thebaron/2014/10/06/hiding-joined-yammer-posts-in-chrome/ where the author of the post has shared his work (https://gist.github.com/thicknrich/e4cc2871462a6850fe8c). This is a simple javascript and does the job.
//Script from https://gist.github.com/thicknrich/e4cc2871462a6850fe8c
//load jQuery based on this SO Post:
//http://stackoverflow.com/questions/2246901/how-can-i-use-jquery-in-greasemonkey-scripts-in-google-chrome
// a function that loads jQuery and calls a callback function when jQuery has finished loading
function addJQuery(callback) {
var script = document.createElement("script");
script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js");
script.addEventListener('load', function() {
var script = document.createElement("script");
script.textContent = "window.jQ=jQuery.noConflict(true);(" + callback.toString() + ")();";
document.body.appendChild(script);
}, false);
document.body.appendChild(script);
}
// the guts of this userscript
function main() {
// Note, jQ replaces $ to avoid conflicts.
setInterval(function() {
//if a item thread contains #joined, hide it
//check every 5 second.
jQ('.yj-thread-list-item:contains("#joined")').css("display", "none");
}, 5000);
}
// load jQuery and execute the main function
addJQuery(main);
You can find all joined messages with the following endpoint, based upon the #joined topic:
GET https://www.yammer.com/api/v1/messages/about_topic/[:id].json
But you can only delete messsages that you own:
DELETE https://www.yammer.com/api/v1/messages/[:id]
Source: https://developer.yammer.com/restapi/
Note that this is a conscious decision by the product team, although joined messages can get spammy when a network becomes viral, it is a great opportunity to engage users right away once they join. It makes them feel welcome. As a community manager, I'd encourage you to welcome that user in and also encourage other yammer champions to welcome these users also. As a side effect, it also encourages people to follow the groups they are interested in and use the Top or Following feeds instead of the all (firehose) feed which has all these joined messages.
Just want to note that the statement in a reply here "But you can only delete messsages that you own" is not entirely correct it is possible to delete message that do not belong to you if you are a network admin. I just ran a little experiment after reading this post and deleting #joined messages that don't belong to me worked just fine.

Birt Reports - Don't generate an empty report

I have several Birt Reports that I am trying to set up to run on a cron job that will email pdfs of the reports every morning. Everything is working fine as far as the generation and emailing goes; the only issue I am stuck with is this: if there is nothing to report, a pdf with just the report title is generated and emailed (a blank report, basically). I'd like to stop this report from being generated at all, so i can skip the emailing, if the pdf file does not exist.
I have been all over Google for two days now, and the closest I can find is this: http://www.eclipse.org/forums/index.php/t/458779/ in which someone was trying to solve a similar problem and received a push in the right direction, but not a complete solution.
It appears as if this can be done during the beforerender script... but how?
I know I need to:
set a persistent global variable in the oncreate if there is indeed data to report.
get the persistent global variable in the beforerender script.
send the magic don't generate report command.
I'm doing all of generating and emailing from a php script, not Java, so I can't send commands like IEngineTask.cancel() (or can I???)
Yes, I know I can make a row in the report that says "No data to report", but that's not what my users want.
And yes, I could query the database outside of the report to determine if there is valid data to report or not, but i'd prefer not to.
And maybe I could even open and read the pdf, programmatically to see if there is anything there, but that sounds like more of a hassle than it's worth...
So, how do I do this?
Thanks.
My answer is a little bit late, but I'm doing it like this in a framework that is working for hundreds of reports, probably it could be simplified for a single report:
Note that all the code is written from memory (not copied from our framework), so maybe it contains some errors.
Add an external Javascript file myframework.js to your report.
In this file, define an object myframework like this:
if (myframework == undefined) {
myframework = {
dataFound: false,
afterReport: function() {
// Write it to the appContext.
// Using Java, you could read it after the
// runAndRenderTask is done.
reportContext.getAppContext().put("dataFound", this.dataFound);
// But since you probably cannot the context
// (don't like coding Java?), the report has to
// tell it to he world some other way...
var txt = "dataFound=" + (dataFound? "true": "false");
var fw = new java.io.FileWriter("c:\\reportcontext.out");
fw.write(txt);
fw.close();
}
};
}
Add the JS file to your report's resources.
In your report, at a place where you decide that the report has found something (e.g. typically in a data set's onFetch event), tell the framework so by calling
myframework.dataFound = true;
In the reports's afterFactory or afterRender event, call
myframework.afterReport();
Then your report should create an output file c:\reportcontext.out which contains the information you need.

django update page when database field updates?

I have a results page and I am trying to work out how to auto update the page when an external database field is updated. I have seen quite a few examples but they seem to relate to PHP. I have a test that calls various APIs that can take up to an hour to complete. Once the test has completed, it will enter a success or failed message in a database field.
I already have my results page being rendered by django using template tags. I have a table and I have the field I would like to update. There are multiple fields that need update which correspond to each API test.
I have seen this site.. is this the kind of stuff to use? http://www.dajaxproject.com/ Is this an easy task to do? Does anyone have any ideas on how to do this?
Sorry but I don't know where to start on this one.
Cheers - Oli
I decided not to be so bold and just use the old classic page update for this purpose using javascript..
window.onload = setupRefresh;
function setupRefresh() {
setTimeout("refreshPage();", 30000); // milliseconds
}
function refreshPage() {
window.location = location.href;
}
Still open for options however I'm rather inexperienced in django and maybe this was too much to bite off too quickly..

how count downloads of a file with jquery

Anyone knows some jquery plugin to count how many times a file (pdf, in my case) is download from your server??
you can simply use the google analytics javascript API with an onclick event
Then you can have beautiful charts for your downloads. see here for an example case : http://think2loud.com/use-jquery-with-google-analytics-to-track-clicks-on-outgoing-links-from-your-site/
You can create script download.php that count your download links.
<?php
// connect to database
if (isset($_GET['file'])) {
$file = mysql_real_escape_string($_GET['file']);
$query = "insert into downloads VALUES('$file', 1) on duplicate key " .
"update count = count + 1;, count+1)";
mysql_query($query);
}
?>
downloads table is:
create table downloads(file VARCHAR(255) primary key, count integer default 1)
and in jQuery
$('a.download').click(function() {
//empty function don't care what I get.
$.get('download.php', {file: $(this).attr('href')}, function() {});
});
it call download.php script with href attribute on every link that have download class
UPDATE I forget to add return false because in code above it call ajax and then abort it.
$('a.download').click(function() {
var link = $(this).attr('href');
$.get('download.php', {file: link}, function() {
// change url to link when ajax is finished
window.location = link;
});
// prevent following the link
return false;
});
You can also add code that prevent multiply clicks because there will be delay between ajax call finish and changing url to link of a element (user may click few times because it will not folow the link) and you can add CTRL+click because it open link in other window (you can return true in this case).
You can use jQuery to determine how many times a single user clicks on a given link on a given fully-rendered page, and use that value to update a database table of download clicks through AJAX, but jQuery doesn't have any direct insight into your server-side data as relates to the total number of downloads, you would have to be updating a database with that data and displaying it from there. you could use jQuery to watch and see if that value changes (on a timer maybe) and update your page accordingly, butthat still requires a AJAX call to a database lookup.
jQuery is a library for Javascript with is a client-side language and acts on the page once it is downloaded and running on the client's machine and as such is not the place for server-side logic and lookups except in the cases where AJAX is warranted and needed.
This is impossible. jQuery code runs in a user's browser, not on a server. To count downloads you'll need server-side code.
jQuery alone won't be able to do that.
You would have to keep track on the server each time the file is requested.
Is there anyway to modify the above script to allow only 1 download per user in a set period of time based on the date they joined the site, i.e. the user can only download the file once per year starting from the day they joined the site?
I'm using Wordpress to run my site.
Thanks

Resources