File Upload to Channel via Microsoft Teams Graph Api - file-upload

I have been trying to do a file upload to a channel using the graph Api. I can successful do an upload to my personal OneDrive, using the request https://graph.microsoft.com:443/v1.0/me/drive/root:/fileName:/content
However I am unable to upload to a channel. I have tried many combinations, but keep getting invalidRequest. Below are some of the request I have tried:
https://graph.microsoft.com:443/v1.0/groups/groupID/drive/items/channelID:/iconfinder_13_3561846_32.png:/content
https://graph.microsoft.com:443/v1.0/groups/groupID/drive/items/channelName:/iconfinder_13_3561846_32.png:/content
I have also tried inputting the channel ID in various ways:
xx:xxxxxxxxxxxxxxxxxxxxxxxxx#thread.tacv2
xxxxxxxxxxxxxxxxxxxxxxxxx#thread.tacv2
xx:xxxxxxxxxxxxxxxxxxxxxxxxx

I found out what I was doing wrong. For anybody else who is having an issue, you have to get the folder id that backs the channel. Here is an example in C#.
// Get the folder of the channel (driveItem)
var item = await graphClient.Teams[teamID].Channels[channelID].FilesFolder
.Request().GetAsync();
// Do the put request
var uploadRequest = graphClient
//.Me.Drive.Root
.Groups[teamID]
.Drive
.Items[item.Id]
.ItemWithPath(file.FileName)
.Content.Request()
.PutAsync<DriveItem>(file.OpenReadStream());

I spent hours with this topic. Your solution wasn't working for me but I finally got it done. To save others I'd like to share my solution too:
I use this to get the drive item for the channel:
var request = graphClient.Teams[teamId].Channels[channelId].FilesFolder.Request().GetAsync();
And then upload with:
var uploadRequest = graphClient.Drives[driveItem.ParentReference.DriveId].Items[driveItem.Id].ItemWithPath("testfile.pdf").Content.Request()
.PutAsync<DriveItem>(System.IO.File.OpenRead(filePath));
My application authenticates with a client secret. Maybe this makes a difference.

Related

Kotlin for Volley, how can I check the JSON request for newer data in the API?

I'm working on an app that gets a list of documents/source URL from an api. I'd like to periodically check for new or updated contents within that API so users can update saved items in the database. I'm at a loss on the correct wording to search, thus Google and Stack Overflow have both failed me. My fetching function is below:
The URL for the API is https://api.afiexplorer.com
private fun fetchPubs() {
_binding.contentMain.loading.visibility = View.VISIBLE
request = JsonArrayRequest(
Request.Method.GET,
Config.BASE_URL,
JSONArray(),{ response ->
val items: List<Pubs> =
Gson().fromJson(response.toString(), object : TypeToken<List<Pubs>>() {}.type)
val sortedItems = items.sortedWith(compareBy { it.Number })
pubsList?.clear()
pubsList?.addAll(sortedItems)
// Hardcoded pubs moved to Publications Gitlab Repo
// https://gitlab.com/afi-explorer/pubs
_binding.contentMain.recyclerView.recycledViewPool.clear()
adapter?.notifyDataSetChanged()
_binding.contentMain.loading.visibility = View.GONE
setupData()
Log.i("LENGTH OF DATA", "${items.size}")
},
{error ->
println(error.printStackTrace())
Toasty.error(applicationContext, getString(string.no_internet), Toast.LENGTH_SHORT, true).show()
}
)
MyApplication.instance.addToRequestQueue(request!!)
}
private fun setupData(){
adapter = MainAdapter(applicationContext, pubsList!!, this)
_binding.contentMain.recyclerView.adapter = adapter
}
I tried using ChatGPT to see if that would get me started and that failed miserably. Also searched Google, Reddit and Stack Overflow for similar projects, but mine is a unique scenario I guess. I'm just a hobbyist and intermediate dev I guess. First time working with Volley, everything works, but I would like to find a way to send a notification (preferably not Firebase) if there is updated info within the API listed above. I'm not sure if this is actually doable.
Are you asking if you can somehow find if the remote API has changed its content? If so, how would that service advise you? If the service provider provides a web hook or similar callback you could write a server-based program to send a push notification to your Android app.
Perhaps you intent to poll the API periodically, and then you want to know if there is a change?
If you use a tool such as Postman or curl to easily see the headers of the API https://api.afiexplorer.com you will see, unfortunately, there is no Last-Modified header or ETag header which would allow you to easily determine if there was a change.
Next looking at the content of the API, the author does not provide an obvious version/change date, so no luck there.
What you could do is receive the content as a String, and perform a checksum operation on it, and if it differs you know there has been a change
or if you are deserialising the received JSON in Kotlin data classes, then out of the box, Kotlin will enable you to perform an equality operation on a previous copy of the data to know if there was a change.
This looks like an android app; if so, why don't you create a background service that makes requests to the API and updates the data as needed? You can use an AlarmManager class to set the interval threshold for polling by using the setInexactRepeating() method.
Most apps are updated in this fashion; sometimes, a separate table is created to catalog changesets.
Let me know if this helps.

Create a space with Google Chat REST API

We have a program that uses a service account to manage various thing inside Google Chat.
Now, we have the need to create a new space using the Google Chat REST API (spaces.create).
We already joined the developer preview program, as this endpoint is not yet generally available.
From what we understand, this endpoint is not possible to invoke via service account and so we wanted to ask you… can we invoke this endpoint automatically using “domain delegation”? If yes, how?
We always want to use the service account as it is not possible to show a login prompt to the user.
We enabled the domain delegation but that endpoint returns always status 403. (We are using Google.Apis library for .NET Core
using Google.Apis.Auth.OAuth2;
var credential = GoogleCredential.FromFile("key.json")
.CreateScoped("https://www.googleapis.com/auth/chat.spaces.create")
.CreateWithUser("service-account-email#project.iam.gserviceaccount.com");
var token = await credential.UnderlyingCredential.GetAccessTokenForRequestAsync();
HttpRequestMessage request = new(HttpMethod.Post, "https://chat.googleapis.com/v1/spaces");
request.Headers.Authorization = new("Bearer", token);
var payload = #"
{
""name"": ""testspace-1"",
""spaceType"": ""SPACE"",
""singleUserBotDm"": true,
""displayName"": ""Test Space""
}
";
request.Content = new StringContent(payload, System.Text.Encoding.UTF8, "application/json");
HttpClient client = new();
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
If you check the documentation Auth
You will notice it stats that service account authorization is supported. If you are part of thedeveloper preview program
The reason I asked about your code is that the last time i tried this which notably was a while ago. The google .net client library was not generated the methods that were under preview.
So while it may work yes. The issue your may have is that the client library when loaded will not have the method you need meaning you will have to code the call to the endpoint yourself.
If this is in fact the case let me know if you have any issues peceing it together I may be able to help.
update your code
There is an error in your code
.CreateWithUser("service-account-email#project.iam.gserviceaccount.com");
The email in CreateWithUser should be the user on your domain who you wish to delicate the service account as. Not the service account email address.

Nest.js and Archiver - pipe stream zip file into http response

In my node.js application I'm downloading multiple user files from AWS S3, compress them to single zip (with usage of Archiver npm library) file and send back to client. All the way I'm operating on streams, and yet I can't send files to client (so client would start download after successful http request).
const filesStreams = await this.awsService.downloadFiles(
document?.documentFiles,
);
const zipStream = await this.compressService.compressFiles(filesStreams);
// ts-ignore
response.setHeader('Content-Type', 'application/octet-stream');
response.setHeader(
'Content-Disposition',
'attachment; filename="files.zip"',
);
zipStream.pipe(response);
Where response is express response object. zipStream is created with usage of Archiver:
public async compressFiles(files: DownloadedFileType[]): Promise<Archiver> {
const zip = archiver('zip');
for (const { stream, name } of files) {
zip.append((stream as unknown) as Readable, {
name,
});
}
return zip;
And I know it is correct - because when I pipe it into WriteStream to some file in my file system it works correctly (I'm able to unzip written file and it has correct content). Probably I could temporarily write file in file system, send it back to client with usage of response.download and remove save file afterwards, but it looks like very inefficient solution. Any help will be greatly appreciated.
So I found a source of a problem - I'll post it here just for record, in case if anyone would have same problem. Source of the problem was something totally different - I was trying to initiate a download by AJAX request, which of course won't work. I changed my frontend code and instead AJAX I used HTML anchor element with src attribute set on exactly same endpoint and it worked just fine.
I had a different problem, but rather it came from the lint. I needed to read all files from the directory, and then send them to the client in one zip. Maybe someone finds it useful.
There were 2 issues:
I mismatched cwd with root; see glob doc
Because I used PassThrough as a proxy object between Archiever and an output, lint shows stream.pipe(response) and type issue... what is a mistake - it works fine.

Handling of Thumbnails in Google Drive Android API (GDAA)

I've run into the following problem when porting an app from REST API to GDAA.
The app needs to download some of (thousands of) JPEG images based on user selection. The way this is solved in the app is by downloading a thumbnail version first, using this construct of the REST API:
private static InputStream getCont(String rsid, boolean bBig){
InputStream is = null;
if (rsid != null) try {
File gFl = bBig ?
mGOOSvc.files().get(rsid).setFields("downloadUrl" ).execute():
mGOOSvc.files().get(rsid).setFields("thumbnailLink").execute();
if (gFl != null){
GenericUrl url = new GenericUrl(bBig ? gFl.getDownloadUrl() : gFl.getThumbnailLink());
is = mGOOSvc.getRequestFactory().buildGetRequest(url).execute().getContent();
}
} catch (UserRecoverableAuthIOException uraEx) {
authorize(uraEx.getIntent());
} catch (GoogleAuthIOException gauEx) {}
catch (Exception e) { }
return is;
}
It allows to get either a 'thumbnail' or 'full-blown' version of an image based on the bBig flag. User can select a thumbnail from a list and the full-blown image download follows (all of this supported by disk-base LRU cache, of course).
The problem is, that GDAA does not have an option to ask for reduced size / thumbnail version of an object (AFAIK), so I have to resort to combining both APIs, which makes the code more convoluted then I like (bottom of the page). Needles to state that the 'Resource ID' needed by the REST may not be immediately available.
So, the question is: Is there a way to ask GDAA for a 'thumbnail' version of a document?
Downloading thumbnails isn't currently available in the Drive Android API, and unfortunately I can't give a timeframe to when it will be available. Until that time, the Drive Java Client Library is the best way to get thumbnails on Android.
We'd appreciate if you go ahead and file a feature request against our issue tracker: https://code.google.com/a/google.com/p/apps-api-issues/
That gives requests more visibility to our teams internally, and issues will be marked resolved when we release updates.
Update: I had an error in the discussion of the request fields.
As Ofir says, you can't get thumbnails with the Drive Android API and you can get thumbnails with the Drive Java Client Library. This page has is a really good primer for getting started:
https://developers.google.com/drive/v3/web/quickstart/android
Oddly, I can't get the fields portion of the request to work as it is on that quick start. As I've experienced, you have to request the fields a little differently.
Since you're doing a custom field request you have to be sure to add the other fields you want as well. Here is how I've gotten it to work:
Drive.Files.List request = mService.files()
.list()
.setFields("files/thumbnailLink, files/name, files/mimeType, files/id")
.setQ("Your file param and/or mime query");
FileList files = request.execute();
files.getFiles(); //Each File in the collection will have a valid thumbnailLink
A sample query might be:
"mimeType = 'image/jpeg' or mimeType = 'video/mp4'"
Hope this helps!

Authentication with SMTP transport using Swiftmailer

I'm using Swiftmailer to send emails in my Yii based application and it works great, so there is no problems with the Swiftmailer extension wrapper. But now I want to use the SMPT transport to authenticate the users in my application against the mail server. The code I'm using:
$SM = Yii::app()->swiftMailer;
$mailHost = 'XXX';
$mailPort = XXX;
// New transport
$transport = $SM->smtpTransport($mailHost, $mailPort);
$transport->setUsername($username);
$transport->setPassword($password);
$transport->start();
if($transport->isStarted()){
// authenticated;
}else{
// error;
}
$transport->stop();
This isn't working. When I set real login credentials instantly logs in. But when I type wrong ones, it spends some time but at last it logs in too. I don't know why this happens because just when using real credentials Swiftmailer can send emails.
I'm using the right API functions? I'm doing something wrong?
Looking at the source, when you call start(), started is always set to True.
I'm not familiar with switfmailer, but it looks like you'll want to check the results of authenticate()