Retrieving screenshot pic from service via controller - javascript

I want to take screenshot with cordova-screenshot-plugin. Can i save that picture as variable or something so i can manipulate with it later? Service for taking screenshot :
.service('$cordovaScreenshot', ['$q', function($q) {
return {
capture: function(filename, extension, quality) {
extension = extension || 'jpg';
quality = quality || '100';
var defer = $q.defer();
console.log(defer);
navigator.screenshot.save(function(error, res) {
if (error) {
console.error(error);
defer.reject(error);
} else {
console.log('screenshot saved in: ', res.filePath);
defer.resolve(res.filePath);
}
}, extension, quality, filename);
return defer.promise;
}
};
}]);
I will try to take screenshot with button, and show it with popup.

The Cordova-Plugin-Screenshot API gives you the file path of the picture. This filepath is accessible from anywhere in the smartphone. So you could use the sample service given in the official github repository with something like that in your controller:
// app is define elsewhere in your application
app.controller('Awesome.Controller', AwesomeController);
AwesomeController.$inject = ['$cordovaScreenshot'];
function AwesomeController($cordovaScreenshot) {
var vm = this;
vm.onClick = takeScreenshot;
function takeScreenshot() {
$cordovaScreeshot.capture('mypic', 'jpg', 80).then(function(filepath) {
vm.filepath = filepath;
}
}
}
With an HTML template like this:
<button on-click="vm.onClick()">take screenshot</button>
<div ng-if="vm.filepath">
<p>Result: {{vm.filepath}}</p>
<img ng-src="{{vm.filepath}}>
</div>

Related

How do I download a Google Sheet with Google Picker all in JavaScript?

I'm trying to implement Google Picker and the Google Drive API in JavaScript on my website. Currently, I use a PHP script to fetch Google Drive documents, but it's using restricted scopes and I want to remove restricted scopes from my application.
First, I got the Google Picker quickstart code working. I tried to add a Google Drive get using the access token that I fetched in the Google Picker code. Google Drive code comes over in the client.js, right? Is the access token used in api.js compatible with the access token used for client.js?
I found an old Gist from six years ago and tried to integrate and update it. Here's my code right now. The gapi.client.drive.files.get fails to get the file.
// Scope to use to access user's photos.
var scope = 'https://www.googleapis.com/auth/drive.file';
var pickerApiLoaded = false;
var driveApiLoaded = false;
var oauthToken;
// Use the API Loader script to load google.picker and gapi.auth.
function onApiLoad() {
gapi.load('auth2', onAuthApiLoad);
gapi.load('picker', onPickerApiLoad);
}
function onClientLoad() {
gapi.client.setApiKey(developerKey);
gapi.client.load('drive', 'v2', onDriveApiLoad);
}
function onAuthApiLoad() {
var authBtn = document.getElementById('auth');
authBtn.disabled = false;
authBtn.addEventListener('click', function() {
gapi.auth2.init({ client_id: clientId }).then(function(googleAuth) {
googleAuth.signIn({ scope: scope }).then(function(result) {
handleAuthResult(result.getAuthResponse());
})
})
});
}
function onPickerApiLoad() {
pickerApiLoaded = true;
createPicker();
}
function onDriveApiLoad() {
driveApiLoaded = true;
}
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
createPicker();
}
}
// Create and render a Picker object for picking user Photos.
function createPicker() {
if (pickerApiLoaded && oauthToken) {
var view = new google.picker.DocsView(google.picker.ViewId.SPREADSHEETS);
//view.setMimeTypes("text/csv");
//view.setMode(google.picker.DocsViewMode.LIST);
view.setQuery(jQuery('[updateparam="name"]').val());
var picker = new google.picker.PickerBuilder().
//addView(google.picker.ViewId.DOCS).
addView(view).
setInitialView(view).
setOAuthToken(oauthToken).
setDeveloperKey(developerKey).
setCallback(pickerCallback).
build();
picker.setVisible(true);
}
}
// A simple callback implementation.
function pickerCallback(data) {
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
var fileId = doc[google.picker.Document.ID];
jQuery('[updateparam="googleDriveFileId"]').val(fileId);
//if (driveApiLoaded) {
var request = gapi.client.drive.files.get({
'fileId': fileId
});
request.execute(function(file) {
var xhr = new XMLHttpRequest();
xhr.open('GET', file.downloadUrl);
xhr.setRequestHeader('Authorization', 'Bearer ' + oauthToken);
xhr.onload = function() {
console.log(xhr.responseText);
};
xhr.onerror = function() {
warningMessage.displayMessage('Failed to download Google Drive document ' + fileId);
};
});
//} else {
// warningMessage.displayMessage('Google Drive API has not been loaded.');
//}
}
// Triggers before Picker is shown
// else {
// warningMessage.displayMessage('No Google Drive document selected.');
//}
}
And my script tags:
<!-- The Google API Loader script. -->
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
<script type="text/javascript" src="https://www.google.com/jsapi?key=KEY"></script>
<script type="text/javascript" src="https://apis.google.com/js/client.js?onload=onClientLoad"></script>
The problem is when you try to retrieve the downloadUrl attribute in file.downloadUrl, which is a field that doesn’t exist anymore in the Drive API version 3 (It was in the version 2), check v2 [1] and v3 [2].
Instead, you should use the webContentLink attribute to download the file, which is available for files with binary content as images, pdf, etc, but not for google docs and sheets (it’s only available the webViewLink attribute which is the url to the file) [2]. For these cases (docs and sheets), you can implement the import method which works for convert google documents and returns the file object [3]. The import request would be like this:
var request = gapi.client.drive.files.import({ 'fileId': fileId, 'mimeType': mimeType });
With mimeType for the target document you want (pdf, txt, etc). Then, inside the callback, access the attribute using file.webContentLink as with the other cases.
[1] https://developers.google.com/drive/api/v2/reference/files
[2] https://developers.google.com/drive/api/v3/reference/files
[3] https://developers.google.com/drive/api/v3/reference/files/export
Through trial and error, I discovered that in order to load both the Google Picker (client:auth2) and the Google Drive API (gapi.client), the Google Picker must be initialized with a callback, and then the Google Drive API is initialized with a Promise that must be chained. If the Promise is not chained, then it will be unresolved and will not work.
// Use the Google API Loader script to load the google.picker script.
function loadPicker() {
gapi.load('auth', {'callback': onAuthApiLoad});
gapi.load('picker', {'callback': onPickerApiLoad});
}
function onAuthApiLoad() {
driveApiLoaded = true;
}
function onPickerApiLoad() {
pickerApiLoaded = true;
}
function askForClientAuthorization() {
gapi.load('client:auth2', function(_) {
window.gapi.client.init({
apiKey: developerKey,
clientId: clientId,
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/drive/v3/rest"],
scope: 'https://www.googleapis.com/auth/drive.file'
})
.then(function(__) {
return gapi.client.drive.files.export({
'fileId': window.googleDriveFileId,
'mimeType': 'text/csv'
})
.then(function(file) {
// Client is authorized to access this file, do something with the file
})
.catch(function(e) {
gapi.auth.authorize(
{
'client_id': clientId,
'scope': scope,
'immediate': false
},
handleAuthResult);
});
})
})
}
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
oauthToken = authResult.access_token;
createPicker();
return true;
} else {
return false;
}
}
// Create and render a Picker object for searching images.
function createPicker() {
if (pickerApiLoaded && oauthToken) {
var view = new google.picker.DocsView(google.picker.ViewId.SPREADSHEETS);
view.setMode(google.picker.DocsViewMode.LIST);
view.setQuery(window.dataFeedName);
var picker = new google.picker.PickerBuilder()
.setAppId(appId)
.setOAuthToken(oauthToken)
.addView(view)
.setDeveloperKey(developerKey)
.setCallback(pickerCallback)
.build();
picker.setVisible(true);
return picker;
}
}
// A simple callback implementation.
function pickerCallback(data) {
if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
// Do work
}
}
With this code, it must check if the user is authorized for every execution.

Cannot delete file because it is being used by another process, ASP.NET Core MVC

I am using ASP.Net Core with MVC for creating an app. I am using visual studio and IIS express currently.
Below is my current project structure:
*project directory
-wwwroot
-areas
-attachments
-controllers
-models
-views
I currently store images inside the attachments folder.
Previously I have written something like that inside my startup.cs
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "Attachments")),
RequestPath = "/Attachments"
});
I have also done something like this below:
appendImage(#Url.Content("~/Attachments/")+result.fileName);
I did this to display an image on my view. The image is displayed successfully.
What I am trying to achieve now is the on the UI allow the user to make a choice to delete the files inside that attachments folder
I tried the following code:
string contentRootPath = _hostingEnvironment.ContentRootPath;
string fullImagePath = Path.Combine(contentRootPath + "\\Attachments", currentItemToDelete.FileName);
if (System.IO.File.Exists(fullImagePath))
{
try{
System.IO.File.Delete(fullImagePath);
}catch(Exception e){
operationResult = "Attachment Path. Internal Server Error";
}
}
The execution does enter the if (System.IO.File.Exists(fullImagePath))
but it raises an exception when it reaches System.IO.File.Delete. The exception states that the file which resides in that path is being used by another process. And thus I cannot delete the file. The only process that is accessing the file is the web app I am creating/debugging at the same time. How do I prevent this exception from happening? Do I have to use other kind of code to delete the file ?
EDIT to include more details:
Inside my view(index.cshtml):
appendImage is a javascript function:
function appendImage(imgSrc) {
var imgElement = document.createElement("img");
imgElement.setAttribute('src', imgSrc);
if (imgSrc.includes(null)) {
imgElement.setAttribute('alt', '');
}
imgElement.setAttribute('id', "img-id");
var imgdiv = document.getElementById("div-for-image");
imgdiv.appendChild(imgElement);
}
That function is called below:
$.ajax({
url:'#Url.Action("GetDataForOneItem", "Item")',
type: "GET",
data: { id: rowData.id },
success: function (result) {
removeImage();
appendImage(#Url.Content("~/Attachments/")+result.fileName);
$("#edit-btn").attr("href", '/Item/EditItem?id=' + result.id);
},
error: function (xhr, status, error) {
}
});
After calling appendImage(); I change the href of a <a> tag. When the user clicks on the link, the user is directed to another page(edit.cshtml). In the page, the image which resides in that path is also being displayed with code like this:
<img src="#Url.Content("~/Attachments/"+Model.FileName)" alt="item image" />
In this new page(edit.cshtml), there is a delete button. Upon clicking the delete button, the execution of the program goes to the controller which is this controller function:
[HttpPost]
public string DeleteOneItem(int id)
{
//query the database to check if there is image for this item.
var currentItemToDelete = GetItemFromDBDateFormatted(id);
if (!string.IsNullOrEmpty(currentItemToDelete.FileName))
{
//delete the image from disk.
string contentRootPath = _hostingEnvironment.ContentRootPath;
string fullImagePath = Path.Combine(contentRootPath + "\\Attachments", currentItemToDelete.FileName);
if (System.IO.File.Exists(fullImagePath))
{
try
{
System.IO.File.Delete(fullImagePath);
}catch(Exception e)
{
}
}
}
return "";
}
EDIT to answer question:
Add in
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
before system.io.file.delete
you can replace your C# method DeleteOneItem with this given code. may be it might work.
[HttpPost]
public string DeleteOneItem(int id)
{
//query the database to check if there is image for this item.
var currentItemToDelete = GetItemFromDBDateFormatted(id);
if (!string.IsNullOrEmpty(currentItemToDelete.FileName))
{
//delete the image from disk.
string contentRootPath = _hostingEnvironment.ContentRootPath;
string fullImagePath = Path.Combine(contentRootPath + "\\Attachments", currentItemToDelete.FileName);
if (System.IO.File.Exists(fullImagePath))
{
try
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.IO.File.Delete(fullImagePath);
}
catch (Exception e) { }
}
}
return "";
}
try
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.IO.File.Delete(fullImagePath);
}
catch(Exception e){
}

AngularJS - Download PDF after trigger generating

I found several articles regarding this topic, but none of them are helping me to that extent that I managed it to download a pdf file with angular.
So the background is, that the user clicks on a button, sends some data to my php script that creates a pdf file. When this is done, the download of the file should start immediately.
The user clicks on this:
<button class="btn pull-right" ng-click="printList(products)">Create list</button>
Then I have this function:
app.controller('Delivery', function($scope, $routeParams, Products, List) {
$scope.printList = function ($products) {
List.save({
'products': $products,
'selectedDate': $scope.state.dates.start
}, function () {
});
};
});
And the factory:
app.factory('List', function($resource) {
return $resource('/backend/FpDashboard/listApi');
});
In PHP I have the action which creates the pdf file on the server, but how can I manage my callback from List.save to start the file download?
Thanks!
I had a same functionality in my project too and this is the code i used to download data as PDF.
downloadAsPdf.getfile(data)
.success(function(data) {
data.fileName = decodeURIComponent(data.fileName);
if(isSafariOrIE){
windowReference.location = data.fileName;
} else {
var save = document.createElement('a');
save.href = data.fileName;
save.target = '_blank';
save.download = data.fileName || 'unknown';
var evt = new MouseEvent('click', {
'view': window,
'bubbles': true,
'cancelable': false
});
save.dispatchEvent(evt);
(window.URL || window.webkitURL).revokeObjectURL(save.href);
}
})

Authenticate on SignalR console application from JS client

Following scenario/my solution consists of the following:
Project one: (SELF HOST) I have a SignalR console application which handles the logic including the authentication process ( queries database with EF ). Project two: (CLIENT) I have an ASP.Net web application with an AngularJS client.
So far I can talk to the hub just fine. The problem is, I cannot seem to get the authentication to work. I've tried a bunch of things I've found but none of them worked. Most of them didn't even apply to my problem..
Currently I've stripped my project back to the basics and I have the following code:
Startup class:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
My hub:
[HubName("systemHub")]
public class systemHub : Hub
{
public void Authenticate(String pLogin, String pPassword)
{
User curUser = new AuthManager().Authenticate(pLogin, pPassword);
//this is where I'd want to send the auth cookie or whatever and contact the "loginCallback" function in my client
}
[Authorize]
public void Hello(String pMessage)
{
Clients.All.callbackFunc(pMessage);
}
}
Js client:
hinagApp.controller('hinagController', function ($scope) {
$(document).ready(function () {
var conURL = 'http://localhost:8080/signalr';
$.getScript(conURL + '/hubs', function () {
$.connection.hub.url = conURL;
var lHub = $.connection.systemHub;
lHub.client.callbackFunc = function(pM){
alert(pM);
}
lHub.client.loginCallback = function (pSuccess) {
if (pSuccess) {
//if logged in
lHub.server.hello("test");
}
else {
alert("fail");
}
}
$('#loginbutton').click(function () {
lHub.server.authenticate($('#input_login').val(), $('#input_pass').val());
});
$.connection.hub.start();
});
})
});
I recently ran into a similar problem. If I understand you right, you want to do the authentication on your signalr server application. Signalr can accept standard webrequests just fine.
Set the authenticationtype to cookies:
CookieAuthenticationOptions lOptions = new CookieAuthenticationOptions()
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
LoginPath = new PathString("/Auth/Login"),
LogoutPath = new PathString("/Auth/Logout"),
};
app.UseCookieAuthentication(lOptions);
If user wants to login, set the claims you'd like to use
var lForm = await context.Request.ReadFormAsync();
if (!String.IsNullOrEmpty(lForm["input_login"]) && !String.IsNullOrEmpty(lForm["input_pass"]))
{
//Benutzer authentifizieren
var lAuthenticatedUser = new UserManager().Authenticate(lForm["input_login"], lForm["input_pass"]);
if (lAuthenticatedUser != null)
{
//Existiert der Nutzer legen wir die Claims an
ClaimsIdentity lIdentity = new ClaimsIdentity(lOptions.AuthenticationType);
lIdentity.AddClaim(new Claim(ClaimTypes.Name, lAuthenticatedUser.Username));
lIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, lAuthenticatedUser.InternalUserId.ToString()));
lIdentity.AddClaim(new Claim(ClaimTypes.SerialNumber, context.Request.RemoteIpAddress));
//Und zum Schluss einloggen
context.Authentication.SignIn(lIdentity);
//Und auf die Spieleseite weiterleiten
context.Response.Redirect(BLL._Configuration.HinagGameURL);
}
}
If you want to serve the login page you can do it like this (_Authpage is your page as String, for example)
else if (context.Request.Path.Value == "/Auth/")
{
if (context.Authentication.User != null)
context.Response.Redirect(BLL._Configuration.HinagGameURL);
context.Response.ContentType = "text/html";
await context.Response.WriteAsync(_Authpage);
}
If the user needs anything else ( such as additional style files in your authpage )
else
{
await next();
}
All of this belongs in your Startup.
In Startup.cs you need to add forms authentication middleware (probably you need to tune it a bit):
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
});
https://msdn.microsoft.com/en-us/library/microsoft.owin.security.cookies.cookieauthenticationoptions(v=vs.113).aspx
You kind screwed up Angular with that code. Try this one:
hinagApp
.controller('hinagController', function ($scope, $http) {
var conURL = 'http://localhost:8080/signalr';
var lHub = $.connection.systemHub;
lHub.client.callbackFunc = function(pM){
alert(pM);
}
lHub.client.loginCallback = function (pSuccess) {
if (pSuccess) {
//if logged in
lHub.server.hello("test");
}
else {
alert("fail");
}
}
$http
.get(conURL + '/hubs')
.then(function(response) {
$.connection.hub.url = conURL;
$('#loginbutton').click(function () {
lHub.server.authenticate($('#input_login').val(), $('#input_pass').val());
});
$.connection.hub.start();
});
});

How to check if page is published

to check if page is published using server side code i should use this snippet:
PublishingPageCollection pages = PublishingWeb.GetPublishingWeb(web).GetPublishingPages();
foreach (PublishingPage page in pages)
{
if(!page.ListItem.File.Level == SPFileLevel.Published)
return;
// logic
}
How could i do the same but using Javascript in SharePoint?
According to SP.Publishing.PublishingWeb Methods the method GetPublishingPages is not supported in JSOM API.
But you could consider the following example to determine whether page is published or not using JSOM API
function getPublishingPages(success,error)
{
var ctx = SP.ClientContext.get_current();
var list = ctx.get_web().get_lists().getByTitle('Pages');
var items = list.getItems(SP.CamlQuery.createAllItemsQuery());
ctx.load(items,'Include(File)');
ctx.executeQueryAsync(function() {
success(items);
},
error);
}
SP.SOD.executeFunc('SP.js', 'SP.ClientContext', function() {
getPublishingPages(printPagesInfo,logError);
});
function printPagesInfo(pages)
{
pages.get_data().forEach(function(item){
var file = item.get_file();
var pageStatus = file.get_level() === SP.FileLevel.published ? 'published' : 'not published';
console.log(String.format('Page {0} is {1}', file.get_name(),pageStatus));
});
}
function logError(sender,args){
console.log('An error occured: ' + args.get_message());
}

Categories