SecondaryTile with unicode character in DisplayName - unicode

I am using this piece of code to create a SecondaryTile.
public static async Task<bool> PinToStartAsync(Playlist playlist, bool isPlaylist)
{
var tilename = playlist.Name;
var tileid = Uri.EscapeDataString(isPlaylist ? tilename : $"{tilename}+++{playlist.Artist}");
var filename = Uri.EscapeDataString(tilename);
var path = LogoPath;
if (playlist.DisplayItem.Source != null && await (await GetSecondaryTileFolder()).TryGetItemAsync(filename) == null)
{
await (await GetStorageItemThumbnailAsync(playlist.DisplayItem.Source.Path)).SaveAsync(SecondaryTileFolder, filename);
path = $"ms-appdata:///local/SecondaryTiles/{filename}.png";
}
var tile = new SecondaryTile(tileid, tilename, isPlaylist.ToString(), new Uri(path), TileSize.Default);
tile.VisualElements.ShowNameOnSquare150x150Logo = tile.VisualElements.ShowNameOnSquare310x310Logo = tile.VisualElements.ShowNameOnWide310x150Logo = true;
if (SecondaryTile.Exists(tilename)) await tile.RequestDeleteAsync();
else await tile.RequestCreateAsync();
return SecondaryTile.Exists(tilename);
}
This piece of code works fine when the playlist name is like 123 or helloworld. However, when I use unicode in the tilename, it causes problem.
Below is an image of SecondaryTiles that I created. The name of first two has some unicode characters.
So it is not able to display the Thumbnail I stored locally, even though I created those images successfully.
Another problem with unicode character is that, the SecondaryTile.Exists(tilename) will always return false.
I have noticed the problem with unicode so I added Uri.EscapeDataString to tileid and filename so that they are uri safe. However, I do want my tiles to have names with unicode characters.
How should I allow unicode characters in tilename?
---Code Update---
public static async Task<bool> PinToStartAsync(Playlist playlist, bool isPlaylist)
{
var tilename = playlist.Name;
var tileid = WebUtility.UrlEncode(isPlaylist ? tilename : $"{tilename}+++{playlist.Artist}");
var filename = tileid + ".png";
var path = DefaultAlbumCoverPath;
if (playlist.DisplayItem.Source != null && !await (await GetSecondaryTileFolder()).Contains(filename))
{
await (await GetStorageItemThumbnailAsync(playlist.DisplayItem.Source.Path)).SaveAsync(SecondaryTileFolder, tileid);
path = $"ms-appdata:///local/SecondaryTiles/" + filename;
}
var tile = new SecondaryTile(tileid, tilename, isPlaylist.ToString(), new Uri(path), TileSize.Default);
tile.VisualElements.ShowNameOnSquare150x150Logo = tile.VisualElements.ShowNameOnSquare310x310Logo = tile.VisualElements.ShowNameOnWide310x150Logo = true;
if (SecondaryTile.Exists(tileid)) await tile.RequestDeleteAsync();
else await tile.RequestCreateAsync();
return SecondaryTile.Exists(tileid);
}

Since the SecondaryTile accesses the image through the path, the entire URI must be path-safe, which is a prerequisite for the software to successfully access the image.
From this perspective, there is nothing wrong with your handling.
In fact, these images are stored in the application's local storage and are not publicly available. The name doesn't need to be concerned.
But you can translate the image name via `Uri.UnescapeDataString()` when exporting these images or you want to get its name.
Update
As you can see from the picture you gave, the tile can display Chinese text (although it is illegible because it is white background + white text), so your question appears on the image.
You don't have to use Uri.EscapeDataString to change the file name, which will exceed the limit when converting long filenames.
You can save the image as the original name, but you can use the following methods when using the link:
string imagePath = $"ms-appdata:///local/SecondaryTiles/{WebUtility.UrlEncode("测试图片")}.png";
Using WebUtility.UrlEncode() in the link can solve this problem well, and the image will be recognized normally.
Another problem with unicode character is that, the SecondaryTile.Exists(tilename) will always return false.
This has nothing to do with Unicode, the main problem is your code:
if (SecondaryTile.Exists(tilename))
await tile.RequestDeleteAsync();
else
await tile.RequestCreateAsync();
Your code has a key problem. When it detects the Tile with the same id, it only deletes it, but does not create a new Tile, so it naturally returns false when it detects.
Best regards.

Related

How to allow users to upload files with Google Form without login?

Where can I find code and instruction on how to allow users to upload files with Google Form without login?
I searched all over here and couldn't find any information.
https://developers.google.com/apps-script/reference
Thanks in advance.
The user will be uploading the files to your drive. So, google needs to verify the user. If there is no verification, someone can fill your drive in no time.
It is for your safety to know who has uploaded, so, login is must.
There's a workaround, I'm in a hurry to write the code now, but if you're interested let me know and I'll edit later.
Basically, you set up a web app with apps script, then you setup a custom HTML form, you'll have to manually collect the file, convert is to base64 then json, then when you catch it in apps script you reverse the process and save it wherever you want in your drive.
Since the user will be executing the script as you, there's no verification required
/*
These functions basically go through a file array and reads the files first as binary string (in second function), then converts the files to base64 string (func 1) before stringifying the files (after putting their base64 content into an object with other metadata attached; mime, name e.t.c);
You pass this stringified object into the body part of fetch(request,{body:"stringified object goes here"})
see next code block for how to read in apps script and save the files to google drive
N.B. The body data will be available under doPost(e){e.postData.contents}
*/
async function bundleFilesForUpload(){
let filesDataObj = [];
let copy = {fileInfo:{"ogname":"","meme":""},fileData:""};
for(let i = 0 ; i < counters.localVar.counters.filesForUploadArr.length ; i++){
let tempObj = JSON.parse(JSON.stringify(copy));
let file = counters.localVar.counters.filesForUploadArr[i];
tempObj.fileInfo.ogname = file.name;
tempObj.fileInfo.meme = file.type;
tempObj.fileData = await readFile(file).then((file)=>{
file = btoa(file);
return file;
}).then((file)=>{
return file;
})
filesDataObj.push(tempObj);
}
return filesDataObj;
}
async function readFile (file){
const toBinaryString = file => new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = () => resolve(reader.result);
reader.onerror = error => reject(error);
});
let parsedFile = null;
parsedFile = await toBinaryString(file);
return parsedFile;
}
/*From doPost downward, we read the file Array convert the base64 to blob and make a file in google drive using the blob and metadata we have, you may also see some sheet code, I'm using sheet as db for this */
//in buit function doPost in Code.gs
doPost(e){
const myDataObj = JSON.parse(e.postData.contents);
mainFileFunc(myDataObj.params[0].dataObj.images);
//the actual object structure might look different from yours, console log around
}
function mainFileFunc(fileArr) {
let myArrObj = [{"madeit":"toFileF"}];
let copy = JSON.parse(JSON.stringify(myArrObj[0]));
//sheet.getRange("A1").setValue(JSON.stringify(fileArr.length));
for(let i=0 ; i < fileArr.length ; i++){
myArrObj.push(copy);
let blob = doFileStuff(fileArr[i].data,fileArr[i].info[0].mime,fileArr[i].id);
myArrObj[i] = uploadFileOne(blob,fileArr[i].id);
myArrObj[i].mime = fileArr[i].info[0].mime;
myArrObj[i].realName = fileArr[i].name;
// sheet.getRange("A"+(i+1)).setValue(myArrObj[i].name);
// sheet.getRange("B"+(i+1)).setValue(myArrObj[i].url);
// sheet.getRange("C"+(i+1)).setValue(myArrObj[i].mime);
// sheet.getRange("D"+(i+1)).setValue(myArrObj[i].size);
}
return myArrObj;
}
function doFileStuff(filedata,filetype,filename){
var data = Utilities.base64Decode(filedata, Utilities.Charset.UTF_8);
var blob = Utilities.newBlob(data,filetype,filename);
return blob;
}
function uploadFileOne(data,filename) {
let myObj = {}
myObj["name"] = "";
myObj["realName"] = "Story_Picture";
myObj["url"] = "";
myObj["mime"] = "";
myObj["size"] = "";
myObj["thumb"] = "nonety";
var folders = DriveApp.getFoldersByName("LadhaWeb");
while (folders.hasNext()) {
var folder = folders.next();
folder.createFile(data);
}
var files = DriveApp.getFilesByName(filename);
while (files.hasNext()) {
var file = files.next();
myObj.name = file.getName();
myObj.url = file.getUrl();
myObj.mime = file.getMimeType();
myObj.size = file.getSize();
}
return myObj;
}
You can view the full frontend code for this project here and the backend here.
Hope this helps someone.

Flutter, How to get all the image file name from images folder?

I want to load all the image file names in images/pets/ to List<String> animals. How can I do that?
path_provider you can get the directory the temp and appDir directory
final directory = await getApplicationDocumentsDirectory();
String imagesDirectory = directory + "/images/pets/";
After you can use the listSync method to find files of this Directory
final myDir = new Directory(imagesDirectory);
List<FileSystemEntity> _images;
_images = myDir.listSync(recursive: true, followLinks: false);
I hope that I have helped in some way
Flutter generates a file called AssetManifest.json which you can read up through the default bundle the same way you would read a normal text file from the assets.
var manifestContent = DefaultAssetBundle.of(context).loadString('AssetManifest.json');
Read and parse this file and then create a list from all the properties you need with their paths. Just double check to make sure you have the correct path, this can change in the future. It seems to me like a placeholder.
Pseudo-code for reading AssetManifest.json
var manifestContent = DefaultAssetBundle.of(context).loadString('AssetManifest.json');
var manifestMap = json.decode(manifestContent);
var imagePetPaths = manifestMap.keys.where((key) => key.contains('images/pets/'));
// You can either use the keys and fetch the value from the map,
or just use the key value since it's the same as the one in the pubspec.yaml
Continuing from AdsHan's Answer
final dir = await getApplicationDocumentsDirectory();
final imagesDirectory = Directory(dir.path + "/images/pets/");
List<String> images = [];
final _imagesFile = imagesDirectory.listSync(followLinks: false, recursive: true);
_imagesFile.forEach((img) {
String imgString = img.toString().substring(
img.toString().lastIndexOf('/') + 1,
img.toString().length);
images.add(imgString);
});

Google script: Download web image and save it in a specific drive folder

I need to download an image with GS and save it in a specific drive folder.
I'm able to save the image in the root folder but i cannot save it in a specific folder:
function downloadFile(fileURL,folder) {
var fileName = "";
var fileSize = 0;
var response = UrlFetchApp.fetch(fileURL, {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob()
var folder = DriveApp.getFoldersByName(folder);
if (folder != null) {
var file = DriveApp.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
}
Question: what have I to add to use the variable "folder"?
I found a lot of examples with "DocList" Class that is not in use anymore
Many thanks
Well, I guess GAS has make a lot of progress on developing its API, the function
createFile(blob) of an object Folder will do the job:
https://developers.google.com/apps-script/reference/drive/folder#createfileblob
// Create an image file in Google Drive using the Maps service.
var blob = Maps.newStaticMap().setCenter('76 9th Avenue, New York NY').getBlob();
DriveApp.getRootFolder().createFile(blob);
It's quite late for the answer but just incase some one runs into the situation.
Are you familiar with this app? It does exactly what you're asking for.
However, if you want to re-create this for your own purposes, I would change your declaration of variable file to read as such:
var file = folder.next().createFile(fileBlob);
when you create your variable folder, the method you use creates a FolderIterator, not a single folder. You have to call the next() method to get a Folder object.
To be precise with your script and avoid saving to an incorrect-but-similarly-named folder, I would recommend passing the folder ID to your script rather than the folder Name. If you pass the folder ID, you could declare folder as:
var folder = DriveApp.getFolderById(folder);
and then continue the script as you have it written. I hope that helps.
Working on similar problem, I came up with the solution below to save a file to a folder. If the folder doesn't exist it creates it, otherwise it saves the file specified by "FOLDER_NAME"
var folderExists = checkFolderExists("FOLDER_NAME");
if (folderExists) {
saveFolder = DriveApp.getFolderById(folderExists);
} else {
saveFolder = DriveApp.createFolder("FOLDER_NAME");
}
// Make a copy of the file in the root drive.
var file = DriveApp.getFileById(sheetID);
// Take the copy of the file created above and move it into the folder:
var newFile = DriveApp.getFolderById(saveFolder.getId()).addFile(file);
// Remove the copy of the file in the root drive.
var docfile = file.getParents().next().removeFile(file);
Further to Eric's answer, I have also provided a utility function that checks if the folder exists. It's reusable in any project.
function checkFolderExists(fName) {
try {
var folderId;
var folders = DriveApp.getFolders();
while (folders.hasNext()) {
var folder = folders.next();
folderName = folder.getName();
if (folderName == fName) {
folderId = folder.getId();
}
}
} catch(e) {
log("Services::checkFolderExists()" + e.toString());
throw e;
}
return folderId;
}

Openxml: Added ImagePart is not showing in Powerpoint / Missing RelationshipID

I'm trying to dynamically create a PowerPoint presentation. One slide has a bunch of placeholder images that need to be changed based on certain values.
My approach is to create a new ImagePart and link it to the according Blip. The image is downloaded and stored to the presentation just fine. The problem is, that there is no relationship created in slide.xml.rels file for the image, which leads to an warning about missing images and empty boxes on the slide.
Any ideas what I am doing wrong?
Thanks in advance for your help! Best wishes
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite siteCollection = new SPSite(SPContext.Current.Site.RootWeb.Url))
{
using (SPWeb oWeb = siteCollection.OpenWeb())
{
SPList pictureLibrary = oWeb.Lists[pictureLibraryName];
SPFile imgFile = pictureLibrary.RootFolder.Files[imgPath];
byte[] byteArray = imgFile.OpenBinary();
int pos = Convert.ToInt32(name.Replace("QQ", "").Replace("Image", ""));
foreach (DocumentFormat.OpenXml.Presentation.Picture pic in pictureList)
{
var oldimg = pic.BlipFill.Blip.Embed.ToString(); ImagePart ip = (ImagePart)slidePart.AddImagePart(ImagePartType.Png, oldimg+pos);
using (var writer = new BinaryWriter(ip.GetStream()))
{
writer.Write(byteArray);
}
string newId = slidePart.GetIdOfPart(ip);
setDebugMessage("new img id: " + newId);
pic.BlipFill.Blip.Embed = newId;
}
slidePart.Slide.Save();
}
}
});
So, for everyone who's experiencing a similar problem, I finally found the solution. Quite a stupid mistake. Instad of PresentationDocument document = PresentationDocument.Open(mstream, true); you have to use
using (PresentationDocument document = PresentationDocument.Open(mstream, true))
{
do your editing here
}
This answer brought me on the right way.

NotesSession.GetDataBase method is returning null value

I have a c# class which was written to read the lotus emails for any attachments and save it to the local drive. It was working fine when I pass "" as first parameter to GetDataBase method and full path of .nsf file of my local system as second argument. But, if I remove "" and I specify my local system full name as first argument it is returning null value.
Is it problem with any permissions? If so, it should not work even when I pass "" as first parameter. Otherwise, should I have any other permissions at system/server level?
Please help me in this issue.
Finally, I could do it in the following way. And I thought of posting it to some one can atleast not to suffer again.
Following code is to read the attachment from the lotus emails and save it to the physical location.
string lotusServerName = ConfigurationSettings.AppSettings["Lotus_Server"].ToString();
string lotusDBFilePath = ConfigurationSettings.AppSettings["Lotus_DB_File_Path"].ToString();
string password = ConfigurationSettings.AppSettings["Password"].ToString();
string sourceFolder = ConfigurationSettings.AppSettings["Source_Folder"].ToString();
string targetFolder = ConfigurationSettings.AppSettings["Target_Folder"].ToString();
string documentsFolder = ConfigurationSettings.AppSettings["Documents_Folder"].ToString();
//Creating the notes session and passing password
NotesSession session = new NotesSession();
session.Initialize(password);
//Getting the DB instance by passing the servername and path of the mail file.
//third param "false" will try to check the DB availability by opening the connection
//if it cannot open, then it returns null.
NotesDatabase NotesDb = session.GetDatabase(lotusServerName, lotusDBFilePath, false);
//Get the view of the source folder
NotesView inbox = NotesDb.GetView(sourceFolder);
//looping through each email/document and looking for the attachments
//if any attachments found, saving them to the given specified location
//moving the read mails to the target folder
NotesDocument docInbox = null;
int docCnt = inbox.EntryCount;
for (int currDoc = 0; currDoc < docCnt; currDoc++) {
docInbox = inbox.GetFirstDocument();
object[] items = (object[])docInbox.Items;
foreach (NotesItem nItem in items) {
if (nItem.Name == "$FILE") {
NotesItem file = docInbox.GetFirstItem("$File");
string fileName = ((object[])nItem.Values)[0].ToString();
NotesEmbeddedObject attachfile = (NotesEmbeddedObject)docInbox.GetAttachment(fileName);
if (attachfile != null) {
attachfile.ExtractFile(documentsFolder + fileName);
}
}
}
docInbox.PutInFolder(targetFolder, true);//"true" creates the folder if it doesn't exists
docInbox.RemoveFromFolder(sourceFolder);
}
//releasing resources
if (session != null)
session = null;
if (NotesDb != null)
NotesDb = null;
if (inbox != null)
inbox = null;
if (docInbox != null)
docInbox = null;
Following is values read from .config file.
The above code will work properly if you alredy have lotus mail client in your system and you are able to access mails from your mail server. You don't require any other previliges.