Access denied, SharePoint app. Copy file to another site collection - sharepoint

UPDATE: I understand now that by installing an app in web scope, it only gets access to the hostweb and appweb. So I tried to batchinstall the app - and now the APP works.
However, the App Part isnt available other than in the App Catalog.
Does Anyone know a way to give the App Part permissions to other site collections, or batch install the App Part so its available in other places than app catalog?
have this code that I'm using for downloading a file from one sitecollection, and trying to upload it to another, in sharepoint online.
I'm getting a 403 that im not allowed to upload the file. The DOWNLOAD is fine.
Does anyone have any clues?
var web;
var hostweburl;
var appweburl;
$(document).ready(function () {
sharePointReady();
});
function sharePointReady() {
hostweburl =
decodeURIComponent(
getQueryStringParameter('SPHostUrl')
);
appweburl =
decodeURIComponent(
getQueryStringParameter('SPAppWebUrl')
);
var scriptbase = hostweburl + '/_layouts/15/';
$.getScript(scriptbase + 'SP.Runtime.js',
function () {
$.getScript(scriptbase + 'SP.js',
function () { $.getScript(scriptbase + 'SP.RequestExecutor.js', copyAndUploadFile); }
);
}
);
}
function getQueryStringParameter(param) {
var params = document.URL.split("?")[1].split("&");
var strParams = "";
for (var i = 0; i < params.length; i = i + 1) {
var singleParam = params[i].split("=");
if (singleParam[0] == param) {
return singleParam[1];
}
}
}
function copyAndUploadFile() {
var targetUrl = "https://sogetiumea-my.sharepoint.com/personal/simonagren_sogetiumea_onmicrosoft_com";
var executor = new SP.RequestExecutor(appweburl);
var fileContentUrl = "_api/SP.AppContextSite(#target)/web/GetFileByServerRelativeUrl('/_catalogs/theme/15/fontscheme003.spfont')/$value?#target='" + hostweburl + "'";
var fileTargetUrl = "_api/SP.AppContextSite(#target)/web/GetFolderByServerRelativeUrl('_catalogs/theme/15')/Files/Add(url='fontscheme003.spfont', overwrite=true)?#target='" + targetUrl + "'";
$.ajax({
url: "_api/contextinfo",
type: "POST",
contentType: "application/x-www-url-encoded",
dataType: "json",
headers: {
"Accept": "application/json; odata=verbose",
},
success: function (data) {
var digest = data.d.GetContextWebInformation.FormDigestValue;
var getFileAction = {
url: fileContentUrl,
method: "GET",
binaryStringResponseBody: true,
success: function (getFileData) {
var results = data.body;
var copyFileAction = {
url: fileTargetUrl,
method: "POST",
headers: {
"Accept": "application/json;odata=verbose",
"X-RequestDigest": digest
},
contentType: "application/json;odata=vebose",
binaryStrinRequestBody: true,
body: getFileData.body,
success: function (copyFileData) {
alert("kopiering gick bra");
},
error: function (ex) {
alert(JSON.stringify(ex));
}
};
executor.executeAsync(copyFileAction);
},
error: function (ex) {
alert(JSON.stringify(ex));
}
};
executor.executeAsync(getFileAction);
},
error: function (ex) {
alert(JSON.stringify(ex));
}
});
}

I used a workaround of sort.
I added the app part to the app catalog, and used a hardcoded value to the mysite site collection (used as source for downloading/copying the file).
Using developer tools I copied the html for the iframe used to show the app part i n the app catalog.
I activated publishing on mysites root site collection.
I added a scripteditor webpart. Then I added the copied iframe code. Voila, now the "app part" works.
At first the app listens to the current user, checks if a personal site exists, else it creates it.
Copies as cusom spcolor file from the mysite "_catalogs/theme/15" to same folder on the current users personal site.
Applies the spcolor file in "Applytheme".
This is based on the idea that Vesa has done with a provider hosted app!

Related

React/Node: Spotify API Error: 404 - No Active Device Found

I've created an app which works for Spotify Premium users only (PUT methods don't work for non-premium users according to Spotify's documentation). It's a ten-question interactive quiz where a playlist generates in your Spotify account, plays it and you have to guess the name of each song. It's generated with a NodeJS Backend and displayed via ReactJS. The game can be demoed here: https://am-spotify-quiz.herokuapp.com/
Code can be reviewed below:
server.js
const express = require('express');
const request = require('request');
const cors = require('cors');
const querystring = require('querystring');
const cookieParser = require('cookie-parser');
const client_id = ''; // Hiding for now
const client_secret = ''; // Hiding
const redirect_uri = 'https://am-spotify-quiz-api.herokuapp.com/callback/';
const appUrl = 'https://am-spotify-quiz.herokuapp.com/#';
/**
* Generates a random string containing numbers and letters
* #param {number} length The length of the string
* #return {string} The generated string
*/
var generateRandomString = function(length) {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
};
var stateKey = 'spotify_auth_state';
var app = express();
app.use(express.static(__dirname + '/public'))
.use(cors())
.use(cookieParser());
app.get('/login', function(req, res) {
var state = generateRandomString(16);
res.cookie(stateKey, state);
// scopes needed to make required functions work
var scope = 'user-read-private ' +
'user-read-email ' +
'user-read-playback-state ' +
'user-top-read ' +
'playlist-modify-public ' +
'playlist-modify-private ' +
'user-modify-playback-state ' +
'user-read-playback-state';
res.redirect('https://accounts.spotify.com/authorize?' +
querystring.stringify({
response_type: 'code',
client_id: client_id,
scope: scope,
redirect_uri: redirect_uri,
state: state
}));
});
app.get('/callback/', function(req, res) {
// your application requests refresh and access tokens
// after checking the state parameter
var code = req.query.code || null;
var state = req.query.state || null;
var storedState = req.cookies ? req.cookies[stateKey] : null;
if (state === null || state !== storedState) {
res.redirect(appUrl +
querystring.stringify({
access_token: access_token,
refresh_token: refresh_token
}));
} else {
res.clearCookie(stateKey);
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
form: {
code: code,
redirect_uri: redirect_uri,
grant_type: 'authorization_code'
},
headers: {
'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')),
},
json: true
};
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
var access_token = body.access_token,
refresh_token = body.refresh_token;
var options = {
url: 'https://api.spotify.com/v1/me',
headers: {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json' // May not need
},
body: { // Likely don't need this anymore!
'name': 'Test Playlist',
'public': false
},
json: true
};
// use the access token to access the Spotify Web API
request.get(options, function(error, response, body) {
console.log(body);
});
// we can also pass the token to the browser to make requests from there
res.redirect(appUrl +
querystring.stringify({
access_token: access_token,
refresh_token: refresh_token
}));
} else {
res.redirect(appUrl +
querystring.stringify({
error: 'invalid_token'
}));
}
});
}
});
// AM - May not even need this anymore!
app.get('/refresh_token', function(req, res) {
// requesting access token from refresh token
var refresh_token = req.query.refresh_token;
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
headers: { 'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')) },
form: {
grant_type: 'refresh_token',
refresh_token: refresh_token
},
json: true
};
request.post(authOptions, function(error, response, body) {
if (!error && response.statusCode === 200) {
var access_token = body.access_token;
res.send({
'access_token': access_token
});
}
});
});
console.log('Listening on 8888');
app.listen(process.env.PORT || 8888);
I have a react component which displays as soon as the user is logged in, called premium.js. If you need all the code, you can see it here. Below are the two PUT methods that I need for my game; one to turn off the shuffle feature and the other one used to play the playlist:
removeShuffle() {
axios({
url: 'https://api.spotify.com/v1/me/player/shuffle?state=false',
method: "PUT",
headers: {
'Authorization': 'Bearer ' + this.state.accesstoken
}
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
}
// Then... play the playlist to get started
playPlaylist(contextUri) {
axios({
url: 'https://api.spotify.com/v1/me/player/play',
method: "PUT",
data: {
context_uri: contextUri
},
headers: {
'Authorization': 'Bearer ' + this.state.accesstoken
}
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error)
})
}
These work perfectly fine when I, the creator of the game, try it; however, I had another premium user try it and found this error:
This doesn't seem to make much sense as I've discovered this error happens with another user, regardless of whether they are using Windows or Mac. Does anyone know what this means, and how can I solve? Thanks in advance!
I've also been using Spotify's API and I eventually got the same error when trying to PUT https://api.spotify.com/v1/me/player/play after an inactivity period, where no device was marked as active (I don't know exactly how long, but no more than a couple of hours).
Apparently one device must be set as active so that you can invoke the play endpoint successfully.
If you want to change the status of a device as active, according to their documentation, you can first try to GET https://api.spotify.com/v1/me/player/devices in order to obtain the list of available devices:
// Example response
{
"devices" : [ {
"id" : "5fbb3ba6aa454b5534c4ba43a8c7e8e45a63ad0e",
"is_active" : false,
"is_private_session": true,
"is_restricted" : false,
"name" : "My fridge",
"type" : "Computer",
"volume_percent" : 100
} ]
}
and then select one of the available devices by invoking the player endpoint PUT https://api.spotify.com/v1/me/player, including:
device_ids Required. A JSON array containing the ID of the device on which playback should be started/transferred.
For example: {device_ids:["74ASZWbe4lXaubB36ztrGX"]}
Note: Although an array is accepted, only a single device_id is currently supported. Supplying more than one will return 400 Bad Request
play with value true if you want to start playing right away.
Most likely you didn't get that error yourself because one of your devices was already active when you tested it. If you have no activity during a couple of hours on your own account and then try to invoke the v1/me/player/play endpoint, I'd expect you to get the same error.
An easy workaround to make sure that this was in fact your problem would be to ask your test user to please start playing a song on the Spotify app (no matter which), then pause it, and then trigger the function on your app that invokes the v1/me/player/play endpoint. That shouldn't return the No active device found error anymore.
The way I understand it is you are trying to play a playlist that does not belong to the current user (/me) Which could be the cause of the error.

Issue in making cross-domain call to Project server oData feed from SharePoint Add-In (app)

I am developing a SharePoint Hosted Add-In which will display project server projects. I am using SP.RequestExecutor to make cross domain calls. It gives me the following error “Cannot find resource for the request ProjectData.”
I have given the Reporting (Project Server) Read permission in AppManifest file. Following is my code.
$(document).ready(function () {
SP.SOD.executeFunc('SP.js', 'SP.ClientContext', initializePage);
});
function initializePage() {
hostweburl = decodeURIComponent(getQueryStringParameter("SPHostUrl"));
appweburl = decodeURIComponent(getQueryStringParameter("SPAppWebUrl"));
var scriptbase = hostweburl + "/_layouts/15/";
$.getScript(scriptbase + "SP.RequestExecutor.js", getProjectList);
}
function getProjectList() {
var executor;
executor = new SP.RequestExecutor(appweburl);
executor.executeAsync({
url: appweburl + "/_api/SP.AppContextSite(#target)/ProjectData/Projects?$filter=ProjectState eq 'In Progress'&$select=ProjectId,ProjectName&#target='" +
hostweburl + "'",
method: "GET",
crossDomain: true,
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var jsonObject = JSON.parse(data.body);
alert(jsonObject.d.results);
},
error: function (error) {
alert(error.body);
}
}
);
}
There is no need to use SP.AppContextSite(#target).
Try below URL -
url: appweburl + "/_api/ProjectData/Projects?$filter=ProjectState eq
'In Progress'&$select=ProjectId,ProjectName"
The permissions for your app should include Read permissions for Reporting.

cross domain issue when accessing sharepoint list from sharepoint app

This is my code
function getListItem(url, listname, id, complete, failure) {
// Getting our list items
$.ajax({
url: url + "/_api/lists/getbytitle('"+ listname +"')/items",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
// Returning the results
complete(data);
},
error: function (data) {
failure(data);
}
});
};
The url is coming correctly, also on checkng the full url parameter in ajax call, it is returning data when i open that in new tab
But since this ajax call is made inside a sharepoint app that is in a different domain, its throwing an error - No 'Access-Control-Allow-Origin' header is present on the requested resource
What change should i make in my site to make that list available for cross domain call.
Info:
the site url is http://www.vignesh.cloudappsportal.com/
The app url is xxxx.apps.cloudappsportal.net/CloudAppsTrial/Pages/Default.aspx
Cross domain calls are blocked by modern web browsers due to security concerns. This is a common issue in web based development and is particularly relevant due to the nature of SharePoint hosted Apps. For example, when accessing data in the parent web (http://consoto.sharepoint.com) from an App (hosted at http://apps.sharePoint.com/SPApp) the calls will be blocked. To get round this you can use the SP.RequestExecutor.js script to relay messages to SharePoint from within the same domain.
Example
function getListItems(hostUrl,appWebUrl, listTitle,success,error)
{
var url = appWebUrl + "/_api/SP.AppContextSite(#target)/web/lists/getbytitle('" + listTitle + "')/items?#target='" + hostUrl + "'";
var executor = new SP.RequestExecutor(appWebUrl);
executor.executeAsync(
{
url: url,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var data = JSON.parse(data.body);
success(data.d.results);
},
error: error
});
}
Usage
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(location.search);
return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
var appWebUrl = getParameterByName('SPAppWebUrl');
var hostUrl = getParameterByName('SPHostUrl');
var scriptbase = hostUrl + '/_layouts/15/';
$.getScript(scriptbase + "SP.RequestExecutor.js", function (data) {
getListItems(hostUrl,appWebUrl, 'Tasks',function(data){
//print list items properties
data.forEach(function(item){
console.log(item.Title);
});
},
function(error){
//error handling goes here...
});
});
About App permissions
An app for SharePoint uses permission requests to specify the permissions that it needs to function correctly. The permission requests specify both the rights that an app needs and the scope at which it needs the rights. These permissions are requested as part of the app manifest. The following picture demonstrates how to grant read access for an App
Follow App permissions in SharePoint 2013 for a more details.

Authenticate to JIRA using node-jira module

I need to connect my application to JIRA API, and I found module node-jira, that should help me with that.
However, I'm having problem with authentication.
Here's what I done (nothing special, but for some reason, it doesn't work):
var JiraApi = require('jira').JiraApi;
var jira = new JiraApi('https', '[url to my jira project]', 443, '[username]', '[password]', '2.0.alpha1');
jira.getCurrentUser(function(error, issue) {
if(error){
console.log(error);
return;
}
console.log('success');
});
I receive:
401: Error while getting current user
Any ideas what could go wrong?
After digging into source code, looks like mentioned method isn't making request properly.
It does this.request instead of this.doRequest. I'll submit it to github repo.
This may give you some ideas; it's not a call to get an issue from JIRA, but it shows how to set up an Atlassian API call (from Google Sheets). You just need to plug in the right URL and Endpoint (for a JIRA issue as an example).
function showAtlassian() {
var html = HtmlService.createHtmlOutputFromFile('atlassianform')
.setWidth(200)
.setHeight(200);
SpreadsheetApp.getUi().showModalDialog(html, 'Atlassian Login');
}
function processAtlassian(myForm) {
var username = myForm.un;
var userpw = myForm.pw;
var myencoded = Utilities.base64Encode(username+":"+userpw);
var headers = {"Authorization" : "Basic " + myencoded};
var options = {
'method': 'get',
"contentType" : "application/json",
"headers": headers,
'muteHttpExceptions': false
}
var ui = SpreadsheetApp.getUi();
url = 'https://---your domain --/wiki/rest/api/user/current';
try {
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response)
var result = ui.alert( 'got valid connection userkey ' + data.userKey );
} catch(error) {
var result = ui.alert( 'invalid user or password: url: '+ url +' err: ' + error.toString());
getatlassian();
}
}
function getatlassian() {
var ui = SpreadsheetApp.getUi();
showAtlassian()
}

Ajax request not working in IIS

This code runs in Visual Studio but not in IIS.
$('#addMessage').click(function () {
var textMessage = $('#ticketMessage').val();
var isInternal = $('#isInternal')[0].checked;
var ticketID = $('#TicketID').val();
$.ajax({
url: '/Ticket/AddMessage',
type: 'POST',
data: { textMessage: textMessage, isInternal: isInternal, ticketID: ticketID },
success: function (data) {
var tbody = $('#allMessages').children()[0];
tbody.innerHTML = tbody.innerHTML + data;
$('#ticketMessage').val("");
$('#isInternal')[0].checked = false;
}
});
});
What to fix in this code for the ajax request to run properly in IIS?
Please check with URL, Because sometimes the URL may point to 404 error page.
Because, the file is hosted in virtual folder. So, Please try with fully URL first, to check if it work fine. Better use Firebug or IE 9 developer tools. we can trace the Ajax requests.
I mean like this
$.ajax({
url: 'http://localhost/yourapplication/Ticket/AddMessage',
type: 'POST',
data: { textMessage: textMessage, isInternal: isInternal, ticketID: ticketID },
success: function (data) {
var tbody = $('#allMessages').children()[0];
tbody.innerHTML = tbody.innerHTML + data;
$('#ticketMessage').val("");
$('#isInternal')[0].checked = false;
}
});

Resources