I'm trying to apply a theme in another site collection via JSOM and REST.
I get a 404, that the file is not found. It doesn't matter if i choose another spcolor or spfont file. The result is still the same.
What am I doing wrong?
var applyTheme = {
url: urlToSiteCollection + "/_api/web/applytheme(
colorpaletteurl='/_catalogs/theme/15/palette007.spcolor',
fontschemeurl='_catalogs/theme/15/fontscheme007.spfont',
backgroundimageurl='/piclibrary/th.jpg',
sharegenerated=true)",
type: "POST",
headers: {
"Accept": "application/json;odata=verbose",
"X-RequestDigest": digest
},
contentType: "application/json;odata=vebose",
success: function (applyThemeData) {
alert("Applyat theme");
},
error: function (ex) {
alert(JSON.stringify(ex));
}
};
$.ajax(applyTheme);
And the JSOM code:
var clientContext = new SP.ClientContext(urlToSiteCollection);
var web = clientContext.get_web();
var colorPaletteUrl = urlToSiteCollection + "/_catalogs/theme/15/palette011.spcolor";
var fontSchemeUrl = urlToSiteCollection + "/_catalogs/theme/15/fontscheme002.spfont";
var backgroundImageUrl = imageUrl;
var shareGenerated = true;
web.applyTheme(colorPaletteUrl, fontSchemeUrl, backgroundImageUrl, shareGenerated);
web.update();
clientContext.executeQueryAsync(onApplyThemeSuccess, OnFailure);
Most likely you are getting this error since the endpoint:
http://<sitecollection>/<site>/_api/web/applyTheme(colorPaletteUrl,fontSchemeUrl,backgroundImageUrl,shareGenerated)
expects values for colorPaletteUrl,fontSchemeUrl,backgroundImageUrl parameters to be specified as server relative url, for example: /<site server relative url>/_catalogs/theme/15/palette007.spcolor
The following example works for me
var siteUrl = _spPageContextInfo.siteServerRelativeUrl;
var options = {
colorpaletteurl: _spPageContextInfo.siteServerRelativeUrl + '/_catalogs/theme/15/palette007.spcolor'
};
applyTheme(siteUrl,options)
.done(function (result) {
console.log("Theme has been applied");
})
.fail(function (ex) {
console.log(JSON.stringify(ex));
});
where
function applyTheme(siteUrl,parameters){
var requestUrl = siteUrl + "/_api/web/applytheme(";
var paramUrls = [];
for(var p in parameters) {
paramUrls.push(p + "='" + options.colorpaletteurl + "'");
}
requestUrl += paramUrls.join(',') + ")";
return $.ajax({url: requestUrl,
type: "POST",
headers: {
"Accept": "application/json;odata=verbose",
"X-RequestDigest": $('#__REQUESTDIGEST').val()
},
contentType: "application/json;odata=vebose",
});
}
When you create a new context using SP.ClientContext(url) the url parameter needs to point to a site within the current site collection. The SharePoint JavaScript client object model does not support access across different site collections.
An alternative would be to use REST or SharePoint's other web services to access the other site.
Related
I am trying to create a Google Classroom course using the Google Classroom API and a service account. I am currently experimenting using JavaScript and I have everything set up and working to get a list of course. I set up a JWT and request an authentication token which I receive.
{"access_token":"----ACCESS TOKEN HERE----------","token_type":"Bearer","expires_in":3600}
When I use this to retrieve a user's course list (via GET) there is no problem. I receive back a proper response with a list of courses which I then display in a table.
When I try to use the same process to try to create a course (via POST), I get a 401 error:
{
"error": {
"code": 401,
"message": "The request does not have valid authentication credentials.",
"status": "UNAUTHENTICATED"
}
}
This is the code I use to authenticate:
function authenticate(callback) {
function b64EncodeUnicode(str) {
str = JSON.stringify(str);
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
// constuct the JWT
var jwtHeader = {
"alg":"RS256",
"typ":"JWT"
}
jwtHeader = JSON.stringify(jwtHeader);
//construct the Claim
var jwtClaim = {
"iss":"psclassroomsync#psclassroomsync.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/classroom.courses https://www.googleapis.com/auth/classroom.rosters",
"sub":"myemail#address.com", //this is an admin account I shouldn't really need this but tried with and without it
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp":(Math.round(new Date().getTime()/1000) + 60 * 10),
"iat":Math.round(new Date().getTime()/1000)
}
jwtClaim = JSON.stringify(jwtClaim);
//construct the signature
var key="-----BEGIN PRIVATE KEY-----Removed-----END PRIVATE KEY-----\n";
var jwtSign = b64EncodeUnicode(jwtSign);
var sJWT = KJUR.jws.JWS.sign("RS256", jwtHeader, jwtClaim, key);
var jwt = jwtHeader + "." + jwtClaim + "." + sJWT;
//request Token
var grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer";
var tokenRequest = "grant_type=" + grantType + "&assertion=" + sJWT;
var postURL = "https://www.googleapis.com/oauth2/v4/token"
request = $j.ajax({
url: postURL,
type: "post",
data: tokenRequest,
success: callback
});
}
This is the code I use to GET the course list. (this works)
$j("#getClasses").click(function(event){
function getClasses(callback){
authenticate(function(data){
console.log(JSON.stringify(data));
var access_token = data["access_token"];
var apiUrl = 'https://classroom.googleapis.com/v1/courses'
var myData = 'teacherId=~(teacheremail)&access_token='+access_token;
var files = $j.ajax({
url: apiUrl,
type: "get",
data: myData,
success: function (data) {
var retreivedClasses = JSON.stringify(data);
for(var i = 0; i < data['courses'].length; i++){
nextObject = data['courses'];
$j('#classListTable').append('<tr><td>' + nextObject[i]['name'] + '</td><td>' + nextObject[i]['courseState'] + '</td><td>' + nextObject[i]['enrollmentCode'] + '</td></tr>');
}
//$j('#classList').text(retreivedClasses);
}
});
});
}
getClasses();
});
This is the code that I use to create a course via POST. I've hard coded a few of the variables for testing but still gives the 401 error.
$j("#createClass").click(function(event){
function createClass(callback){
authenticate(function(data){
console.log(JSON.stringify(data));
var access_token = data["access_token"];
var tokenInfo = $j.ajax({
url: 'https://www.googleapis.com/oauth2/v3/tokeninfo',
type: 'get',
data: "access_token="+access_token
});
var apiUrl = 'https://classroom.googleapis.com/v1/courses'
var myData = 'access_token='+access_token + '&ownerId=myemail#address.com&name=myClass'
console.log(myData);
var newGoogleClassroom = $j.ajax({
url: apiUrl,
type: "post",
data: myData,
success: function (data) {
var apiResponse = JSON.stringify(data);
$j('#classCreated').text(apiResponse);
}
});
});
};
createClass();
});
Finally, this is what I get when I get the token info. It looks fine to me i.e. proper scopes: (but I am new at this)
{
"azp": "removed",
"aud": "removed",
"scope": "https://www.googleapis.com/auth/classroom.courses https://www.googleapis.com/auth/classroom
.rosters",
"exp": "1474512198",
"expires_in": "3600",
"access_type": "offline"
}
I'd be grateful for any help.
Doug
P.S. I get the security implications of this code. It is in a secure environment for experimentation only. It won't see the light of day.
Based from this forum which is also receiving a 401 error, try to revoke the old oauth. As stated in this related thread, the 401 Unauthorized error you experienced may be related to OAuth 2.0 Authorization using the OAuth 2.0 client ID.
Suggested action: Refresh the access token using the long-lived refresh token. If this fails, direct through the OAuth flow.
I have been stuck at this problem for almost two days now and I don't seem to find any solution. I have hosted a WCF service on my machine that contains a method SendCredentials which accepts two string parameters.
Now I am supposed to send a public key to my service through which it will do encryption(Asymetric cryptography) and send some information back to the client.
I am not able to pass that public key to the service method from the client as it is in XML format.Here is my client side code:
$(document).ready(function () {
$("#btnSend").click(function () {
debugger;
jQuery.support.cors = true;
var doOaepPadding = true;
var rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
_privateKey = rsa.ToXmlString(true);
_publicKey = rsa.ToXmlString(false);
var data = $("#txtName").val();
var name = "testvalue";
var _privateKey = rsa.ToXmlString(true);
**var _publicKey = rsa.ToXmlString(false);**
//<![CDATA[ and ]]>;
$.ajax({
type: "POST",
url: 'http://localhost:51348/TestService.svc/SendCredentials',
crossDomain: true,
data:JSON.stringify({ mac: "bac", pubKey: _publicKey }),
contentType: "application/json",
dataType: "json",
success: function (result) {
var ans = JSON.stringify(result);
alert(ans);
// result = new XMLSerializer().serializeToString(result.documentElement);
},
error: function (xhr, err) {
alert("readyState: " + xhr.readyState + "\nstatus: " + xhr.status);
alert("responseText: " + xhr.responseText);
}
});
return false;
});
});
</script>
_publicKey is the variable I want to pass but throws above said error. Any suggestions How do i pass this XML variable would be really appreciated.
I would suggest you to convert _publicKey to base64 string
convert your _publicKey to string then byte Array and use
Convert.ToBase64String(byte[] inArray)
and on the service side do the reverse
System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(endodedString), true));
i have tried to update,checkout,checkin AND retrive the checkin comment but im getting value does not fall within the range error? anything i have missed ?
var getfileurl = document.getElementById("getfileurl").value;
//i have entered the path like /lib/folder/test.docx
alert(getfileurl);
var executor;
// Initialize the RequestExecutor with the app web URL.
executor = new SP.RequestExecutor(appweburl);
executor.executeAsync({
url: appweburl + "/_api/SP.AppContextSite(#target)/web/GetFileByServerRelativeUrl('" + getfileurl + "')/CheckInComment?#target='" + hostweburl + "'",
method: "GET",
headers: {
"Accept": "application/json; odata=verbose"
},
success: SuccessHandler,
error: ErrorHandler
});
The error:
Value does not fall within the expected range
occurs since serverRelativeUrl parameter for SP.Web.getFileByServerRelativeUrl Method should be specified as server-relative URL for the file, for example:
/_api/web/GetFileByServerRelativeUrl('/site/web/library/filename')
Solution
Specify file url in the following format:
/site/hostweb/library/filename
for example:
var fileurl = _spPageContextInfo.siteServerRelativeUrl + "/documents/filename";
Good day everyone,
I am facing a slight problem.
Up until last week our mobile application connected to an in-house Web Api, which in turn connected to web services run and maintained by our partners.
Problem is, we would like the remove our Web Api as the middle man, and connect directly from our Cordova app (Javascript) to the Restful service.
Below is the C# code I am trying to emulate, any and all help would be appreciated:
(At this point I'm sure everything is right, except the authentication but I might be wrong)
QUESTION:
How can I achieve this in Javascript (If it is at all possible)
public static AuthenticateResult CheckLogin(LoginModel login)
{
var serviceClient = new WebClient();
var proxy = serviceClient.Proxy;
proxy.Credentials = new NetworkCredential("username_goes_here", "password_goes_here");
serviceClient.Headers["Content-type"] = "application/json";
try
{
var requestHeader = new UnauthenticatedRequestHeader
{
Code = ConstantModel.PartnerCode,
Partner = ConstantModel.PartnerName
};
var authenticateRequest = new AuthenticateRequest
{
Username = login.Username,
Password = login.Password,
Handset = "iPhone Emulator"
};
var serviceRequest = new
{
header = requestHeader,
request = authenticateRequest
};
var jsonizedServiceRequest = JsonConvert.SerializeObject(serviceRequest);
var requestBytes = Encoding.UTF8.GetBytes(jsonizedServiceRequest);
var requestStream = new MemoryStream(requestBytes);
var ms = requestStream.ToArray();
var responseBytes = serviceClient.UploadData("Url_goes_here", "POST", ms);
var jsonizedServiceResponse = Encoding.UTF8.GetString(responseBytes);
var authResult = JsonConvert.DeserializeObject<AuthenticateResponse>(jsonizedServiceResponse);
return authResult.AuthenticateResult;
}
catch (Exception ex)
{
return null;
}
}
What I have so far in Javascript is (this returns a Bad Request error):
btnTestClick: function () {
var header = {
Code: 'guid_goes_here',
Partner: 'partnerid_goes_here'
};
var request = {
Username: 'username_goes_here',
Password: 'password_goes_here',
Handset: 'iPhone Emulator'
};
var myrequest = {
header: header,
request: request
};
var string = JSON.stringify(myrequest);
var data = tobytearray(string);
$.ajax({
type: "POST",
url: "url_goes_here",
crossDomain: true,
data: data,
contentType: 'application/octet-stream;',
dataType: "json",
username: 'auth_username_goes_here',
password: 'auth_password_goes_here',
processData: false,
success: function (result) {
debugger;
},
error: function (jqXHR, textStatus, errorThrown) {
alert("error");
},
beforeSend: function (xhr) {
},
});
function tobytearray(str) {
var bytes = [];
for (var i = 0; i < str.length; ++i) {
bytes.push(str.charCodeAt(i));
}
return bytes;
}
}
What I see from your examples is the difference in the dataType used in the 2 examples.
In the C# example you use serviceClient.Headers["Content-type"] = "application/json"; and in the javascript implementation you use contentType: 'application/octet-stream;'.
octet-stream should be used for attachments and not JSON objects.
The webservice could be validating the request on the content-Type and if the test result is that your request is invalid it can return (and should return) a HTTP 400 - Bad Request.
I don't know the webservice where you shoot your requests at and what validations it does but try changing that contenttype in the javascript implementation to contentType: 'application/json;'.
In my App, I get a list of Events from a Sharepoint Calendar List. That part works perfectly.
However after I get the collection of results, for each item I need to get the Display Form Url, which is another REST Call with the ListItem ID.
However I get the error below, but I still dont know what the problem might be
Uncaught ReferenceError: error is not defined App.js:87(anonymous function) App.js:87$.ajax.error App.js:40c jquery-1.9.1.min.js:22p.fireWith jquery-1.9.1.min.js:22k jquery-1.9.1.min.js:24send.r
I based my code on this answer:
https://sharepoint.stackexchange.com/questions/119236/how-to-get-the-display-form-url-using-rest
My adapted code is like this:
var SPHostUrl;
var SPAppWebUrl;
var ready = false;
// this function is executed when the page has finished loading. It performs two tasks:
// 1. It extracts the parameters from the url
// 2. It loads the request executor script from the host web
$(document).ready(function () {
var params = document.URL.split("?")[1].split("&");
for (var i = 0; i < params.length; i = i + 1) {
var param = params[i].split("=");
switch (param[0]) {
case "SPAppWebUrl":
SPAppWebUrl = decodeURIComponent(param[1]);
break;
case "SPHostUrl":
SPHostUrl = decodeURIComponent(param[1]);
break;
}
}
// load the executor script, once completed set the ready variable to true so that
// we can easily identify if the script has been loaded
$.getScript(SPHostUrl + "/_Layouts/15/SP.RequestExecutor.js", function (data) {
ready = true;
getItems();
});
});
function getListItemFormUrl(webUrl, listName, listItemId, formTypeId, complete, failure) {
$.ajax({
url: webUrl + "/_api/web/lists/GetByTitle('" + listName + "')/Forms?$select=ServerRelativeUrl&$filter=FormType eq " + formTypeId,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
var url = data.d.results[0].ServerRelativeUrl + '?ID=' + listItemId
complete(url);
},
error: function (data) {
failure(data);
}
});
}
// this function retrieves the items within a list which is contained within the parent web
function getItems() {
// only execute this function if the script has been loaded
if (ready) {
// the name of the list to interact with
var listName = "Events";
// the url to use for the REST call.
var url = SPAppWebUrl + "/_api/SP.AppContextSite(#target)" +
// this is the location of the item in the parent web. This is the line
// you would need to change to add filters, query the site etc
// "/web/lists/getbytitle('" + listName + "')/items?" +
"/web/lists/getbytitle('" + listName + "')/items?$select=Title,Category,EventDate,Description,EncodedAbsUrl,ID" +
"&#target='" + SPHostUrl + "'";
// create new executor passing it the url created previously
var executor = new SP.RequestExecutor(SPAppWebUrl);
// execute the request, this is similar although not the same as a standard AJAX request
executor.executeAsync(
{
url: url,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
// parse the results into an object that you can use within javascript
var results = JSON.parse(data.body);
var events = [];
$.each(results.d.results, function (i, obj) {
//Usage
getListItemFormUrl(SPAppWebUrl, 'Calendar', obj.ID, 4,
function (url) {
console.log('Display from url for list item: ' + url);
},
function (sender, args) {
console.log(JSON.stringify(error));
})
//use obj.id and obj.name here, for example:
var event = {
date: Date.parse(obj.EventDate).toString(),
type: obj.Category,
title: obj.Title,
description: obj.Description,
url: obj.EncodedAbsUrl + 'DispForm.aspx?ID=' + obj.ID
}
events.push(event);
});
var myJsonString = JSON.stringify(events);
$("#eventCalendarInline").eventCalendar({
jsonData: events,
openEventInNewWindow: true,
showDescription: true,
txt_GoToEventUrl: "Go to event"
});
Communica.Part.init();
},
error: function (data) {
// an error occured, the details can be found in the data object.
alert("Ooops an error occured");
}
});
}
}
Under //Usage:
function (sender, args) {
console.log(JSON.stringify(error));
})
error does not seem to be defined