Pulling Drive activity report through GCP, is there a way to see folder path? - google-cloud-platform

I am supposed to generate drive activity report so we can track what type of file users are using and where is the file being created (My Drive/shared drive).
I used the GAM command to pull drive activity report which has various fields except for the root path.
Does anyone know a way i can manipulate that so i can get a field that shows folder path as well.
Thanks!

You can try these particular GAM commands so you can edit them later to gather information of the folders and root folders:
gam user <User Email Address> print filetree depth 0 showmimetype gfolder excludetrashed todrive
You can edit the depth, for example orphaned folders when using -1. I am not familiar with which command you use, but you might need to mix or add some fields so it shows the root folder or path.
gam user <User Email Address> print filelist todrive select 1Yvxxxxxxxxxxxxxxxxxxxxxxjif9 showmimetype gfolder fields id
You might need to add over your command something like "print filetree" or "show filepath"
Reference:
https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display

I have created a custom menu that iterates through a table of data, the data must have a column with the file IDs of interest and 2 additional columns for owner and path, since the file can be owned by either a user or a shared drive. The user running the function must have Super Admin rights to access files owned by other users and the user in question must be a member of a shared drive for the file to be located. My previous implementation as a custom function failed to address a limitation of this feature where advanced services are inaccessible.
The custom menu is created as explained in this documentation article https://developers.google.com/apps-script/guides/menus. There must be a trigger that executes when the sheet opens the menu is created.
In addition to that the code requires the use of Advanced Services, Google Drive must be added following the steps of this other article https://developers.google.com/apps-script/guides/services/advanced#enable_advanced_services. The advanced service will ask for authorization but the first time the code is executed. You may expedite the process by creating an empty function and running it.
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('File ownership').addItem('Read data', 'readData').addToUi();
}
function readData() {
var sheetData = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
var i = 0;
for (; i < sheetData.length; i++){
if (sheetData[0][i] == '')
break;
}
SpreadsheetApp.getUi().alert('There are ' + i + ' cells with data.');
for (i = 1; i < sheetData.length; i++){
var fileID = sheetData[i][0];
var owner = getFileOwner(fileID);
var path = getFilePath(fileID);
SpreadsheetApp.getActiveSheet().getRange(i + 1,2).setValue(owner);
SpreadsheetApp.getActiveSheet().getRange(i + 1,3).setValue(path );
}
SpreadsheetApp.getUi().alert('The owner and file path have been populated');
}
function getFilePath(fileID, filePath = ""){
try {
var file = Drive.Files.get(fileID,{
supportsAllDrives: true
});
if (!file.parents[0])
return "/" + filePath;
var parent = file.parents[0];
var parentFile = Drive.Files.get(parent.id,{ supportsAllDrives: true });
var parentPath = parentFile.title;
if (parent.isRoot || parentFile.parents.length == 0)
return "/" + filePath;
else {
return getFilePath(
parentFile.id,
parentPath + "/" + filePath);
}
}
catch (GoogleJsonResponseException){
return "File inaccesible"
}
}
function getFileOwner(fileID){
try {
var file = Drive.Files.get(
fileID,
{
supportsAllDrives: true
});
var driveId = file.driveId;
if (driveId){
var driveName = Drive.Drives.get(driveId).name;
return driveName + "(" + driveId + ")";
}
var ownerEmailAddress = file.owners[0].emailAddress;
return ownerEmailAddress;
}
catch (GoogleJsonResponseException){
return "File inaccesible"
}
}
After executing the function, it will take significantly longer the more files IDs it has, the cells will be updated with their respective owner and path.
Note: with a Super Admin account you can programmatically create a view permission for shared drives you don't have access to using APIs or Apps Script, you may submit a separate question for more details or read the documentation in the developer page at https://developers.google.com/drive/api/v2/reference/permissions.

Related

Rally Web Services API: How do I get the URL link of the user story? (getDetailUrl() method)

Please be patient and Do Not flag this as duplicate: Using the Rally REST API, how can I get the non-API (website) URL for a user story?
I want to be able to generate a link for the user story.
Something like this: https://rally1.rallydev.com/#/-/detail/userstory/*********
As opposed to this: https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement/88502329352
The link will be integrated into another application for the managers to see the user story.
I did read about the getDetailUrl() method, but in my case I am creating the user stories by parsing email and linking that to a notification service in Slack.
I am aware of the formattedID and (_ref), but I would have to query for it again, and I am creating batches of userstories through a loop. I need the actual web site link to the user story.
Here is my sample code:
public void CreateUserStory(string workspace, string project, string userstoryName){
//authenticate with Rally
this.EnsureRallyIsAuthenticated();
//DynamicJsonObject for HierarchicalRequirement
DynamicJsonObject toCreate = new DynamicJsonObject();
toCreate[RallyConstant.WorkSpace] = workspace;
toCreate[RallyConstant.Project] = project;
toCreate[RallyConstant.Name] = userstoryName;
try
{
//Create the User Story Here
CreateResult createUserStory = _api.Create(RallyConstant.HierarchicalRequirement, toCreate);
Console.WriteLine("Created Userstory: " + "URL LINK GOES HERE");
}
catch (WebException e)
{
Console.WriteLine(e.Message);
}
}
We don't have a method in the .NET toolkit for doing this, but it's easy to create.
The format is this:
https://rally1.rallydev.com/#/detail/<type>/<objectid>
Just fill in the type (hierarchicalrequirement turns into userstory, but all the others are the same as the wsapi type) and the objectid from the object you just created.
var parameters = new NameValueCollection();
parameters["fetch"] = "FormattedID";
var toCreate = new DynamicJsonObject();
var createResult = restApi.create("hierarchicalrequirement", toCreate, parameters);
var type = Ref.getTypeFromRef(createResult.Reference);
var objectID = Ref.getOidFromRef(createResult.Reference);
var formattedID = createResult.Object["FormattedID"];
And you can specify fetch fields to be returned on the created object so you don't have to re-query for it.

Google Script if statement does not check user vs entered data

I have a booking program in Google Sheets where a user can pick their name (uses data verification to provide a list of emails) and then the cell is then placed under protection so no other user can change the booking.
The strange thing that happens is that a person can enter in another person's email and then the cell is protected by the entered email not the user. The user can enter in a non-email string and it does not protect the cell.
The desired result would be that if the user's email and the data entered is the same, protect the cells otherwise it is free to be edited.
Any help would be appreciated!
function onEdit(e){
var CurrentUser = Session.getEffectiveUser().getEmail()
var range_DataEntered = SpreadsheetApp.getActiveRange();
var DataEntered = range_DataEntered.getValue();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var SheetName = SpreadsheetApp.getActiveSheet();
var Cell = ss.getActiveCell();
if (CurrentUser = DataEntered) {
var protection = range_DataEntered.protect()
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
protection.addEditor(CurrentUser);
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
else {
//remove protection, set everyone to edit
range_DataEntered.protect().setDomainEdit(true);
}
}
if (CurrentUser = DataEntered) needs to be
if(CurrentUser === DataEntered)
A single = will assign a value not check for equivalency.

Sharepoint 2013 - Open search result in new window/tab

Ok, so I've been struggling with this problem for a few hours now...
I need to modify the links in the search results, so that they open in a new window/tab.
Specifically it's the search results that links to a "off-site"-hit.
I've created a copy of Item_WebPage.html, but I just can't get it to work.
I guess that there are some kind of async loads that screws it all up.
My js-code is as follows:
var anchors = document.getElementsByClassName('ms-srch-item-link');
for (var i = 0; i < anchors.length; i++) {
anchors[i].setAttribute("target", "_blank");
}
}
However, "anchors" always is "0".
Is there a "sharepoint-document-ready-as-h*ll"-function I can use?
My guess is that my problem is that not all content is loaded into the DOM before I run my code...
A custom display template is a good way of changing the behavior of the search results. I've used JQuery code to make sure that external links always load in a new window :
<script type="text/javascript">
if (window.jQuery) {
$(window).load(function () {
// Open external links in a new tab
var url = '://' + window.location.hostname;
// get the current website name, and i add :// to make sure we're looking at the right name //
url = url.toLowerCase(); // lowercase everything to compare apples to apples
$("a").each(function () {
var link = this; // assign the link object to another variable for easier managability
var linkHref = link.href.toLowerCase(); // lower case it
if (linkHref.indexOf(url) < 0 && linkHref.indexOf('javascript:') < 0) { // check to see if this A object has this domain in it and make sure it's not a javascript call
link.target = '_blank'; // change the target to be in the new window
} if (linkHref.indexOf('.pdf') > 0) { // check to see if this is a PDF
link.target = '_blank'; // change the target to be in the new window
$(link).removeAttr("onclick"); //remove the SP click event
} if (linkHref.indexOf('/forms/') > 0 && linkHref.indexOf(').aspx') > 0) { //check for links in the forms library
link.target = '_blank'; // change the target to be in the new window
$(link).removeAttr("onclick"); //remove the SP click event
}
});
});
}
</script>
It's way too long and you may have resolved it.
I was looking for the same and added - target="_blank" to the anchor tag in a custom display template
In SharePoint online, this worked perfectly for me, applies to all results though.
Using SharePoint Designer, update the Item_CommonItem_Body.html Display Template from within _catalogs/masterpage/display templates/search.
Search for below line :
var titleHtml = String.format('<a clicktype="{0}" id="{1}" href="{2}" class="ms-srch-item-link" title="{3}" onfocus="{4}" {5} >{6}</a>',
and replace it with :
var titleHtml = String.format('<a clicktype="{0}" id="{1}" href="{2}" class="ms-srch-item-link" title="{3}" onfocus="{4}" {5} target="_blank">{6}</a>',
Save the change and, from the browser master page library, publish a major version. When you search now the results should open in new tabs although you may need to load the page cache again (CTRL+F5).
From https://social.technet.microsoft.com/Forums/ie/en-US/a7db8389-3740-4ff6-ac52-645776b29a56/search-results-in-new-tabwindow-in-sharepoint-2013

Retrieve data from ParseUser after using FindAsync

I've created a number of users in Parse. There're Facebook users and non-Facebook user. For each Facebook user I've saved an extra column of "facebookID".
Now I'd like to get all the ParseUsers that are Facebook Users. So I applied a Task to query the users with "facebookID" in them.
var Task = ParseUser.Query.WhereExists("facebookID").FindAsync().ContinueWith(t=>{
if (t.IsFaulted || t.IsCanceled) {
Debug.Log ("t.Exception=" + t.Exception);
//cannot load friendlist
return;
}
else{
fbFriends = t.Result;
foreach(var result in fbFriends){
string id = (string)result["facebookID"];
//facebookUserIDList is a List<string>
facebookUserIDList.Add(id);
}
return;
}
});
The above code works perfectly. However, I'd like to get more data from each Facebook User, for example, the current_coins that the user has. So I change the foreach loop to:
foreach(var result in fbFriends){
string id = (string)result["facebookID"];
int coins = (int)result["current_coins"];
//facebookUserIDList is a List<string>
facebookUserIDList.Add(id);
}
I've changed the facebookUserIDList into a List<Dictionary<string,object>> instead of a List<string> in order to save the other data as well. But the foreach loop does not run at all. Does it mean I can only get the facebookID from it because I specified WhereExists("facebookID") in FindAsync()? Can anybody explain it to me please?
Thank you very much in advance.
it should contain all Parse primitive data type(such as Boolean, Number, String, Date...) for each Object. but not Pointers nor Relation.
for Pointers, you can explicitly include them in the result using the "Include" method
for any ParseRelation you have to requery them

Sitecore poll module sample code

I installed and configured the Poll Module to work fine. The website I am working on will have a Poll instance on a page either as a left rail or a right rail item. The Polls would be setup in a separate folder. On the page item there will be a multilist field which will point to the Polls folder and the user can select whichever poll they choose to. The folder will also contain different sublayouts which will could be selected to be displayed on the rail. I have some custom code which will look at the above mentioned multilist field and show these rail items.
I don't know how to display a Poll programmatically. I haven't found any code samples and also not sure where to set the sublayout. Should I set it on the Poll template itself and then let use code to display it? How can I achieve this in code? Any code samples would be helpful.
Hoping that you will this time accept the answer, I wrote the following for you (based on the OMS Poll module:
Read out the field on your item:
Sitecore.Data.Fields.ReferenceField selectedPoll = (Sitecore.Data.Fields.ReferenceField)Sitecore.Context.Item.Fields["Poll"];
Get the pollItem:
if (selectedPoll.TargetItem != null)
{
Item pollItem = selectedPoll.TargetItem;
if (pollItem != null)
{
Check if the poll is opened or closed and place:
Sitecore.Data.Fields.CheckboxField pollClosed = (Sitecore.Data.Fields.CheckboxField)pollItem.Fields["Closed"];
if (pollClosed.Checked == false)
{
// Set the header of the snippetBlock
ltPollHeader.Text = pollItem.Name;
PollVotingSublayout pollSublayout = (PollVotingSublayout)LoadControl("/sitecore modules/Shell/Poll Module/Controls/PollVotingSublayout.ascx");
pollSublayout.Attributes.Add("sc_parameters", "PollPath=" + pollItem.Paths.FullPath);
pollSublayout.CurrentPoll = (PollItem)pollItem;
this.pollRegion.Controls.Add(pollSublayout);
phPollSnippet.Visible = true;
int blockPos = 0;
if (snippetField != null)
{
if (snippetField.GetItems().Any())
{
blockPos = 1;
}
}
string cssClass = String.Empty;
if (blockPos == 0)
{
cssClass = "snippetColHomeFirst";
}
this.SetClass("snippetColHome", cssClass);
}
Hope that you can make up something using this snippets. Good luck!
There should be a user account called "poll" on the sitecore domain. This account is normally used internal by the poll. In the comment of this account is stated: "Please do not remove this account". the account should have the Sitecore Minimal Page Editor role. I don't know the poll user credentials, but you might find that by either using reflector or opening cs files that you can get by downloading the source.