I am trying to create a new subsite of another site in SP Online using the Graph SDK GraphServiceClient. I have successfully authenticated but I cant seem to get a site created - documentation is scarce as are examples so its basically hit and miss and I don't wish to use Graph REST for this purpose. Any help out there? The below code returns a Site object with an error of "invalid request". I'm sure I must be missing some required properties for the new Site object but which ones?
ItemReference parent = new ItemReference();
parent.Id = SiteRootForSubsite.Id;
Site newSite = new Site
{
ParentReference = parent,
Name = SubsiteName,
WebUrl = "/documentcenter909/mynewsite"
};
Site createdSite = await _graphClient.Sites
.Request()
.AddAsync(newSite);
Unfortunately you don't have the feature to create the site at this point as it only has Read only properties for the site. Being said that you can use the following workaround - can create an office 365 group, then assign owners & members then you will see a new SharePoint Online site will be created automatically.
Related
I have a fundamental lack of understanding of implementing security with OAuth. All of the examples I see use the same pattern, so I'm pretty confident my premise is wrong, and the examples are right!
Generally I see it added along these lines.
.AddOAuth("auth", options =>
{
options.ClientId = "id";
options.ClientSecret = "secret";
options.CallbackPath = new PathString("/signin");
options.Scope.Add("scope");
options.AuthorizationEndpoint = "https://.../authorize";
options.TokenEndpoint = "https://.../token";
options.UserInformationEndpoint = "https://.../userinfo";
options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id");
options.ClaimActions.MapJsonKey(ClaimTypes.Name, "name");
options.Events = new OAuthEvents
{
OnCreatingTicket = async context =>
{
var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
var response = await context.Backchannel.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
response.EnsureSuccessStatusCode();
var user = JObject.Parse(await response.Content.ReadAsStringAsync());
context.RunClaimActions(user);
}
};
Now to my fundamental misunderstanding. I want to make a demo application that, for example, has a couple of pages that show the result of some rest api calls. These calls all require an access token. Once the code reaches OnCreatingTicket, the access token has been acquired, and it is used to get data from the UserInformationEndpoint. However, I have several different end points that I want the user to select from (and there may not even be a "UserInformationEndpoint" for the api I'm trying to call..).
So, I think I have a bogus idea about how I'm supposed to do this. Could someone spin me around and point me in the right direction?
Edit because its too long for a comment:
My requirement is just to write a demo app that demonstrates making calls to a api directory.
For the sake of the demo I just imagine a page with a series of links/buttons that take you to a page showing the data returned from different api calls.
In the example above (and all the examples i've seen so far) the authorization is setup at the server level and used to retrieve user information. For my demo getting user information back and displaying it might be nice, but its not the end goal. The fact that all of the examples center on using the toke a single time to get user info is what confuses me. I'm assuming (perhaps incorrectly) that I should get the token once and use it repeatedly from different points in the application.
I'm having trouble understanding if I am fundamentally misunderstanding how to approach this since I tend to imagine if all the examples I find are doing the same thing, they are doing it correctly.
It depends on the endpoint but the way I usually get the user's profile information is by adding scopes. For example, if your endpoint allows access to user profiles, inside your oauth options, request that scope when you authenticate the user:
options.Scope.Add("profile");
This should get it done with less traffic back and forth to the endpoint.
For example, I recently had the same issue with the Google API. I don't remember the exact name of the scope but I requested "profile" scope or something like that and it sent me email, first name, and last name. When I didn't request this scope it only sent me the user id.
I've got an app that has been running using CredentialsAuthProvider() for a while.
Today, I'd like to add twitter and facebook as options for people to create an account. I've got the scaffolding in place.
//Register all Authentication methods you want to enable for this web app.
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new CredentialsAuthProvider(),
new TwitterAuthProvider(appSettings),
new FacebookAuthProvider(appSettings)
}));
//Provide service for new users to register so they can login with supplied credentials.
Plugins.Add(new CustomRegistrationFeature());
The endpoints /api/auth/twitter and /api/auth/facebook work, and I see that a user session is created by visiting /api/auth once the OAuth process is complete HOWEVER...
No user is created in my UserAuthRepository (OrmLiteAuthRepository). The User Id stored in the session is invalid. Any method decorated with the [Authenticate] attribute causes a 404 (User not found) error to be returned.
I would expect that a user is created with the First/Last/Email obtained from Facebook or Twitter. Am I misunderstanding something?
ServiceStack v4.0.38
A few things to check would be the oauth.CallbackUrl has been set correctly taking into account the multiple providers you have registered. Eg http://localhost/auth/{0}.
Also you should check if your IDbConnectionFactory used with your OrmLiteAuthRepository has also been registered with the IoC container. Eg
var dbFactory = new OrmLiteConnectionFactory(
"~/App_Data/db.sqlite".MapHostAbsolutePath(),
SqliteDialect.Provider);
container.Register<IDbConnectionFactory>(dbFactory);
var authRepo = new OrmLiteAuthRepository(dbFactory);
container.Register<IUserAuthRepository>(authRepo);
authRepo.InitSchema();
I wanted to update this thread to say that I've upgraded to ServiceStack 4.0.42 and this issue has resolved itself.
we constructed the new tag JSON like
data:{
name:"busy Tag"
notes:"This is new tag to b created in API"
workspace:"xyz456987"
}
on post http request to /tags api we get the response
data = {
color = "<null>";
"created_at" = "2014-07-19T12:59:13.162Z";
followers = (
);
id = 14895043902988;
name = "busy tag";
notes = "This is new tag to b created in API";
workspace = {
id = 6486925687953;
name = t;
};
};
Yet the created tag doesn't appear in the web app tags list and also the api call doesn't retrieve the newly created tag.
UPDATE:
when i put id of the new tag in the address bar like
https://app.asana.com/0/14896850962516/14896850962516
shows the tag in the webapp. Yet the api call is unable retrieve the the newly created tag item.
I'll quote my answer from Asana tag API query often misses newly created Tags:
The answer is that tags which aren't associated with any tasks are - unfortunately - hidden in the app, and consequently also in the API. As you discovered, you can get the ID back from the POST to create and then associate it with a task from there (since there's little purpose in creating a tag if you're not associating it with something that shouldn't typically be a problem, but it is clunky). We are looking at changing our data model for tags to be a bit more intuitive in future, but that's still a ways off, so this is the reality for the foreseeable future.
I'm very new to Umbraco and have a requirement to set up a site where different customers will access the same site, but see it with their own brand. It must be the same site in IIS and re-using the same razor views and related code, but our business teams have a requirement to set up a new customer for the same site, with their own values for the configurable content data via Umbraco without relying on support or developer involvement.
eg. Site URL is www.mysite.com
Customer from ClientA visits (maybe via URL www.mysite.com/ClientA or perhaps www.mysite.com?brand=ClientA) and sees the version branded for them.
A customer from ClientB should be able to visit the same site but passing in their brand code instead and see their customized version.
My first question is: Is this acheivable? If so, what is the correct way to do it?
I want to maximise code re-use.
Any help or pointers would be hugely appreciated.
Thanks in advance.
You can do this is standard asp.net, add a code behind for the standard default.aspx page that umbraco uses to drive everything and then in the onpreinit event switch either the master page or theme to the correct branding; something like:
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
int templateId = umbraco.NodeFactory.Node.GetCurrent().template;
umbraco.template template = new umbraco.template(templateId);
string templateName = template.TemplateAlias;
if (Request.QueryString["brand"] = "ClientA")
{
Page.MasterPageFile = string.format("~/MasterPages/clienta/{0}.master", templateName);
}
}
So all content is tagged to the standard set of masterpages in the masterpages folder; but if a "?brand=ClientA" url is requested it automatically changes the masterpage to the clienta folder - allowing you to brand the page based on the querystring.
I have an existing MVC3 application which allows users to upload files and share them with others. The current model is that if a user wants to change a file, they have to delete the one there and re-upload the new version. To improve this, we are looking into integrating WebDAV to allow the online editing of things like Word documents.
So far, I have been using the .Net server and client libraries from http://www.webdavsystem.com/ to set the website up as a WebDAV server and to talk with it.
However, we don't want users to interact with the WebDAV server directly (we have some complicated rules on which users can do what in certain situations based on domain logic) but go through the previous controller actions we had for accessing files.
So far it is working up to the point where we can return the file and it gives the WebDAV-y type prompt for opening the file.
The problem is that it is always stuck in read-only mode. I have confirmed that it works and is editable if I use the direct WebDAV URL but not through my controller action.
Using Fiddler I think I have found the problem is that Word is trying to talk negotiate with the server about the locking with a location that isn't returning the right details. The controller action for downloading the file is "/Files/Download?filePath=bla" and so Word is trying to talk to "/Files" when it sends the OPTIONS request.
Do I simply need to have an action at that location that would know how to respond to the OPTIONS request and if so, how would I do that response? Alternatively, is there another way to do it, perhaps by adding some property to the response that could inform Word where it should be looking instead?
Here is my controller action:
public virtual FileResult Download(string filePath)
{
FileDetails file = _fileService.GetFile(filePath);
return File(file.Stream, file.ContentType);
}
And here is the file service method:
public FileDetails GetFile(string location)
{
var fileName = Path.GetFileName(location);
var contentType = ContentType.Get(Path.GetExtension(location));
string license ="license";
var session = new WebDavSession(license) {Credentials = CredentialCache.DefaultCredentials};
IResource resource = session.OpenResource(string.Format("{0}{1}", ConfigurationManager.AppSettings["WebDAVRoot"], location));
resource.TimeOut = 600000;
var input = resource.GetReadStream();
return new FileDetails { Filename = fileName, ContentType = contentType, Stream = input };
}
It is still very early days on this so I appreciate I could be doing this in entirely the wrong way and so any form of help is welcome.
In the end it seems that the better option was to allow users to directly talk to the WebDAV server and implement the authentication logic to control it.
The IT Hit server has extensions that allow you to authenticate against the forms authentication for the rest of the site using basic or digest authentication from Office. Using that along with some other customisations to the item request logic gave us what we needed.
This is exactly what i did for a MVC 4 project.
https://mvc4webdav.codeplex.com/