Retrieve each member's personal and owned shared folders - dropbox-api

I'm trying to iterate through each member in our Dropbox and return their owned folders not shared with anyone and their owned shared folders. The owned shared folder seems pretty straight forward: Use the /2/sharing/list_folders (/continue if needed), which gives all the shared folders the member is part of, and then select only the folders that have an access type of owner. Correct me if this isn't the approach to get all of the user's owned shared folders.
Getting all of the user's owned personal folders seems a bit trickier. My initial thought is to use the /2/files/list_folder and /2/files/list_folder/continue endpoints to retrieve all of the user's folders they have access to (i.e. personal owned folders, owned shared folders, and shared folders with user (but not owner)). My function for getting all these folders is as follows:
public static async Task<List<FolderMetadata>> IterateListFolderResults(DropboxClient userClient){
Boolean hasMore = true;
string hasMoreCursor = "";
var userFolders = new List<FolderMetadata>();
ListFolderResult firstLayer = await userClient.Files.ListFolderAsync("", true, false, false, false, true, null, null, null, true);
var firstLayerFolders = firstLayer.Entries.Where(entry => entry.IsFolder).Select(f => f.AsFolder).ToList();
userFolders.AddRange(firstLayerFolders);
if (firstLayer.HasMore == true)
{
hasMore = true;
hasMoreCursor = firstLayer.Cursor;
do
{
try
{
var nextLayer = await userClient.Files.ListFolderContinueAsync(hasMoreCursor);
var lfolders = nextLayer.Entries.Where((entry) => entry.IsFolder).Select(f => f.AsFolder).ToList();
userFolders.AddRange(lfolders);
if (nextLayer.HasMore == true)
{
hasMoreCursor = nextLayer.Cursor;
}
if (nextLayer.HasMore == false)
{
hasMore = false;
}
}
catch (HttpException err)
{
Console.WriteLine(err);
}
}
while (hasMore == true);
}
return userFolders;
}
Once I have these results the next step is to only keep the folders that the member personally owns and isn't shared. To do this I'm thinking I can compare the master list of all the folders the member participates in against the list of all the shared folders the member participates in. Something like the following:
var nonSharedFolders = memberFolders.Where(mFolder => !sharedFolders.Entries.Any(sharedFolder => sharedFolder.PathLower == mFolder.PathLower));
If I understand correctly, this would return me all the folders the user owns that they haven't shared with anyone?

Related

How to call script include from the client script service-now without GlideAjax

The common process we follow today to get the data on client script:
OnChange client script:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var user = g_form.getValue('u_user');
//Call script include
var ga = new GlideAjax('global.sampleUtils'); //Scriptinclude
ga.addParam('sysparm_name', 'getUserDetails'); //Method
ga.addParam('userId',user); //Parameters
ga.getXMLAnswer(getResponse);
function getResponse(response){
console.log(response);
var res = JSON.parse(response);
console.log(res);
g_form.setValue('u_phone',res.mobile_phone);
g_form.setValue('u_email',res.email);
}
}
Script include:
var sampleUtils = Class.create();
sampleUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getUserDetails: function(){ //Function
var userId = this.getParameter('userId'); //Params
obj = {};
var grSysUser = new GlideRecord('sys_user');
if (grSysUser.get(userId)) {
obj.mobile_phone = grSysUser.getValue('mobile_phone');
obj.email = grSysUser.getValue('email');
}
gs.addInfoMessage(obj+JSON.stringify(obj));
return JSON.stringify(obj);
},
type: 'sampleUtils'
});
DEMO Link: https://youtu.be/nNUsfglmj_M
As an alternative to glideAjax you can EfficientGlideRecord
new EfficientGlideRecord('sys_user')
.addQuery('sys_id', newValue) //On Change client script, we will get sys_id of user in newValue variable
.addField('mobile_phone', true) //Get display value
.query(function (egrSysUser) {
if(egrSysUser.next()) {
g_form.setValue('phone', egrSysUser.getDisplayValue('mobile_phone'));
}
});
What is EfficientGlideRecord?
EfficientGlideRecord is the best alternate way to use GlideAjax.
It is a client-side API class from which you can perform asynchronous client-side GlideRecord-style queries while maximizing performance.
Benefits:
Low code configuration with Huge performance improvement.
No need to worry about security loopholes, because it enforces ACLs.
No more concerns about creating new client callable script includes and maintaining
the logic there.
Dependencies:
To use the EfficientGlideRecord we need to commit the attached update-set or find the latest version from the given link https://github.com/thisnameissoclever/ServiceNow-EfficientGlideRecord/releases.
Add the package to Portal record -> JS Includes.
and that's it, and you are good at using the EfficientGlideRecord syntax.
To know more about EfficientGlideRecord, Refer the below link(s):
https://snprotips.com/efficientgliderecord

How to check firebase storage directory already exist

How can I check if the Firebase Storage directory already exists in Flutter?
There is no way to check if a "folder" exists in Cloud Storage.
This might sound strange, but you have to consider that folders don't actually exist in a bucket-based storage. Cloud Storage doesn't actually have any folders.
The files in the storage just have path metadata associated with them, so that we humans can think hierarchically like we do with folders.
If you want to know if a file exists (not a "folder"), then in your code you could await getMetadata(); on a StorageReference that refers to the file you're looking for.
A workaround could be to create a dummy file such as "readme.md" inside each folder; that would certify its existence. If you can't find such file, your folder (probably) doesn't exist. This implies you carefully add such "dummy" file every time you add a folder.
firebase.database().ref("path/node/").on('value', (snapshot) => { console.log(snapshot.exists()); });
The answer from #venir is useful in understanding what's going on but you can overcome the problem by using this approach.
You can check if a folder exists by checking whether its parent folder contains a folder named after the one you are looking for. Something like this (excuse the TypeScript):
const beforeLast = (str: string, strLast: string) => {
return str.substr(0, str.lastIndexOf(strLast))
}
const afterLast = (str: string, strLast: string) => {
return str.substr(str.lastIndexOf(strLast) + 1)
}
private doesStorageFolderExist(storagePath: string): Observable<any> {
const parentPath: string = beforeLast(storagePath, '/')
const folderName: string = afterLast(storagePath, '/')
const ref: AngularFireStorageReference = this.storage.ref(parentPath)
const listAll: Observable<ListResult> = ref.listAll()
return listAll.pipe(
map((listResult: ListResult) => {
const storagePathExists: boolean = listResult.prefixes.some((folderRef) => folderRef.name === folderName)
return { storagePath, storagePathExists }
})
)
}
Obviously, this only works if there is a parent folder, but often this will be the case. You have to not like Firebase very much for making things so hard!

Using variables or constants in nextjs api

I'm trying to use a constant in my API. This constant is an array where I can push or pop objects. I populate it through API calls. This is the code:
const washes = [];
export default async (req, res) => {
if(req.method === 'GET')
{
res.json({washes});
}
if(req.method === 'POST')
{
washes.push(req.body);
console.log(washes);
res.json({washes});
}
}
I make calls from the front-end to populate the array and to retrieve it. The problem is that, sometimes I get an empty array an sometimes I get the expected array. Or after a while I always get the empty array, like if it was restarted.
I deployed the application on Vercel.
Is there something I'm missing from the back-end functionality, or is it related to Vercel?. Last but not least is it a good practice to use variables or constants in back-end.?
You cant use an array as storage. You need to connect it to a database of sorts.
When you use this endpoint it will only retrieve the correct array sometimes, because it's stored in a temporary memory on the server.
Look into firebase if you easily want to setup up a project and store information in a database.
https://firebase.google.com/docs/web/setup
Another way is to use a .json file in the back-end
Read more here: https://jasonwatmore.com/post/2021/08/28/next-js-read-write-data-to-json-files-as-the-database
USER EXAMPLE
const fs = require('fs');
// users in JSON file for simplicity, store in a db for
production applications
let users = require('data/users.json');
export const usersRepo = {
getAll: () => users,
getById: id => users.find(x => x.id.toString() === id.toString()),
find: x => users.find(x),
create,
update,
delete: _delete
};
function create(user) {
// generate new user id
user.id = users.length ? Math.max(...users.map(x => x.id)) + 1 : 1;
// set date created and updated
user.dateCreated = new Date().toISOString();
user.dateUpdated = new Date().toISOString();
// add and save user
users.push(user);
saveData();
}
function update(id, params) {
const user = users.find(x => x.id.toString() === id.toString());
// set date updated
user.dateUpdated = new Date().toISOString();
// update and save
Object.assign(user, params);
saveData();
}
// prefixed with underscore '_' because 'delete' is a reserved word in javascript
function _delete(id) {
// filter out deleted user and save
users = users.filter(x => x.id.toString() !== id.toString());
saveData();
}
// private helper functions
function saveData() {
fs.writeFileSync('data/users.json', JSON.stringify(users, null, 4));
}

How do I get more than the default attributes from the Microsoft Graph API when requesting all users?

I am trying to get all users from one AAD tenant with a specified schema extension.
However, when doing this request:
GraphServiceClient client = new GraphServiceClient(new AuthProv(_authHelper.GetAuthenticationResult().Result));
var userList = new List<User>();
var users = await client.Users.Request().GetAsync();
userList.AddRange(users.CurrentPage);
while (users.NextPageRequest != null)
{
var nextPage = users.NextPageRequest.RequestUrl;
Debug.WriteLine("Call To: " + users.NextPageRequest.RequestUrl);
users = users.NextPageRequest.GetAsync().Result;
userList.AddRange(users);
}
I am receiving a JSON object that looks like:
[{"businessPhones":[],"displayName":"some account name","userPrincipalName":"somemail#email.com","id":"123","givenName":null,"jobTitle":null,"mail":null,"mobilePhone":null,"officeLocation":null,"preferredLanguage":null,"surname":null}, ...]
However, I have customized an own attribute for users so I can retrieve values from that, but that attribute is not sent with the API response.
How can I change the request so that all user attributes are retrieved as a reponse?
Use this new baseUrl: "https://graph.microsoft.com/beta/"
GraphServiceClient client = new GraphServiceClient("https://graph.microsoft.com/beta/",new AuthProv(_authHelper.GetAuthenticationResult().Result),null);
It seems that you were using open extensions. If yes, we need to expand the extensions explicitly.
Here is the code to print the value of open extensions for your reference:
foreach (var user in users.CurrentPage)
{
if (user.Extensions != null&& user.Extensions.CurrentPage!=null)
{
var customProperty = user.Extensions.CurrentPage.FirstOrDefault(ext => ext.Id == "Com.Contoso.Deal");
if (customProperty != null)
Console.WriteLine($"{user.UserPrincipalName}--{customProperty.Id}:{customProperty.AdditionalData["companyName"]}");
}
}
while (users.NextPageRequest != null)
{
var nextPage = users.NextPageRequest.RequestUrl;
users = users.NextPageRequest.GetAsync().Result;
foreach (var user in users.CurrentPage)
{
var customProperty = user.Extensions.CurrentPage.First(ext => ext.Id == "Com.Contoso.Deal");
if (customProperty != null)
Console.WriteLine($"{user.UserPrincipalName}--{customProperty.Id}:{customProperty.AdditionalData["companyName"]}");
}
}
If there are multiple pages of open extension, you also should retrieve it via the NextPageRequest. Please feel free to let me know if you still have the problem.

Entity Framework: Attached Entities not Saving

I can't figure out why calling SaveChanges() on the following code results in no changes to the objects I attached:
public void Update()
{
AccountUser accountUser = new AccountUser();
// update
using (var db = new MedicalSystemDBEntity())
{
var query = from user in db.AccountUsers
where user.id == this.UserID
select user;
if (query.Count() > 0)
{
accountUser = query.First();
accountUser.AccountRoles.Load();
accountUser.SecurityNavigationNodes.Load();
// delete existing user roles before re-attaching
if (accountUser.AccountRoles.Count > 0)
{
foreach (AccountRole role in accountUser.AccountRoles.ToList())
{
accountUser.AccountRoles.Remove(role);
}
}
db.SaveChanges();
// get roles to add
List<int> roleIDs = new List<int>();
foreach (UserRole r in this.AccountRoles)
{
roleIDs.Add(r.RoleID);
}
var roleEntities = from roles in db.AccountRoles
where roleIDs.Contains(roles.id)
select roles;
accountUser.AccountRoles.Attach(roleEntities);
accountUser.username = this.Username;
accountUser.firstname = this.FirstName;
accountUser.middlename = this.MiddleName;
accountUser.lastname = this.LastName;
accountUser.enabled = this.Enabled;
if (this.LastActivityDate != null || this.LastActivityDate != DateTime.MinValue)
accountUser.lastactivitydate = this.LastActivityDate;
db.SaveChanges();
}
}
}
In the debugger, I see that the correct roleEntities are being loaded, and that they are valid objects. However, if I use SQL Profiler I see no UPDATE or INSERT queries coming in, and as a result none of my attached objects are being saved.
They're not saving because you change the entities before attaching them. Changes are tracked by the context (usually), so changes to detached entities aren't tracked. Hence, nothing to save.
Off the top of my head, shouldn't you do SaveChanges() after you've removed the roles from the account? Aren't you just removing the roles attached to the user, then reattaching the same ones? Since its saving the changes, nothing would have changed would it?
Sometimees its because the entit objects were modified while detached. The post here will show how to clear that up.