How to delete items attachement from sharepoint List using pnpjs? - sharepoint

Hi Im trying to delete attached item from list items first and then upload new attach file in sharepoint using pnp js (in vuejs)!
i trace the code and delete part is runnging but i dont konw why attached file doesnt delete!!!
this is my code for deleting attached item
public async DeleteItemsAttachment(itemId: number): Promise<any> {
let item = pnp.sp.web.lists.getById('{128EF67A-FDSF-4F42-8E8F-D3FC9523273E}').items.getById(itemId)
return await item.attachmentFiles.deleteMultiple()
}
public async AddanAttachment(itemId: number, fileName: string, arrayBuffer: File): Promise<any> {
let item = pnp.sp.web.lists.getById('{128EF6AA-FD8F-4F42-8E8F-D3FC9523273E}').items.getById(itemId)
return await item.attachmentFiles.add(fileName, arrayBuffer)
}
uploadFile(){
if (this.itemId != null && this.myfiles) {
if (this.HasUploadFile) {
this.spService.DeleteItemsAttachment(this.itemId).then(response => {
this.AddAnAttachmentToRecord()
}).catch(e => {
this.message = ` exception : ${e}`
})
}
else {
this.AddAnAttachmentToRecord()
}
}
How can i solve my problem?
where is wrong area of my code?

According to attachmentfiles.ts deleteMultiple function expects the array of attachment file names, so attachments could be deleted by explicitly providing file names:
item.attachmentFiles.deleteMultiple("{attachment-file-name-1}","{attachment-file-name-2}")
or (more dynamic way) by reading attachment names and specifying it in deleteMultiple function:
let item = sp.web.lists.getByTitle(listTitle).items.getById(itemId);
//1. get all attachments
let attachments = await item.attachmentFiles.get();
let attachmentNames = attachments.map(a => a.FileName);
//2. delete all attachmanents
await item.attachmentFiles.deleteMultiple(...attachmentNames);

Related

Firebase does not recognize document path

So I have the following request with which I am trying to do the following:
Look for a collection with the name 'questionnaires'
Look at a specific document with id, given by the parameter of the function
Take the reference of a collection 'questions' within this document
public async getQuestionnaire(
questionnaireId: string,
): Promise<FirebaseFirestore.CollectionReference<DocumentData>> {
const questionsCollection = await getFirestore().collection(
'questionnaires/{questionnaireId}/questions/',
);
return questionsCollection;
}
I tried both by obtaining the reference in one line or seperating it the following way:
public async getQuestionnaire(
questionnaireId: string,
): Promise<FirebaseFirestore.CollectionReference<DocumentData>> {
const questionnairesCollection =
getFirestore().collection('questionnaires');
const desiredQuestionnaire = questionnairesCollection.doc(questionnaireId);
const questions = desiredQuestionnaire.collection('questions');
return questions;
}
The method is called from the following get request handler:
#Get('/firebase/questionnaire/:questionnaireId')
#OpenAPI({ summary: 'Return a questionnaire' })
async getQuestionnaire(#Param('questionnaireId') questionnaireId: string) {
const questionsRef = await this.firebaseService.getQuestionnaire(
questionnaireId,
);
return { data: questionsRef };
}
The interesting thing is that if I print out the reference, I get exactly what I want. However when I try to return it, I get the following error:
[GET] /firebase/questionnaire/3iz5K3hsVvaFBwkyzd57 >> StatusCode:: 500,
Message:: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.

missing permissions in list

for the command to work it needs 3 permissions, but how could I reduce its size and simplify it for it to identify the missing ones and send a list, and not go from one in one?
e.g.
list = {
USE_EXTERNAL_EMOJIS: 'use external emojis',
EMBED_LINKS: 'embed links',
READ_MESSAGE_HISTORY: 'read message history'
}
CODE:
if (!message.channel.permissionsFor(client.user).has('USE_EXTERNAL_EMOJIS' && 'EMBED_LINKS')) {
return message.channel.send('missing permissions use external emojis and embed links');
}
if (!message.channel.permissionsFor(client.user).has('EMBED_LINKS')) {
return message.channel.send('missing permission embed links');
}
if (!message.channel.permissionsFor(client.user).has('USE_EXTERNAL_EMOJIS')) {
return message.message.channel.send('missing permission use external emojis');
}
if (!message.channel.permissionsFor(client.user).has('READ_MESSAGE_HISTORY')) {
return message.channel.send('missing permission read message history');
}
You can use Object.entries() to get an iterable array of key - value pairs and use a method like this
const neededPermsObj = {
USE_EXTERNAL_EMOJIS: 'use external emojis',
EMBED_LINKS: 'embed links',
READ_MESSAGE_HISTORY: 'read message history'
}
const missingPerms = [];
for (const [key, value] of Object.entries(neededPermsObj)) {
if (!message.channel.permissionsFor(client.user).has(key.toString())) {
missingPerms.push(`${key}: ${value}`)
}
}
if (missingPerms.length != 0) return message.channel.send(missingPerms.join('\n')); // prevent from running cmd
else // execute command code here
This would check if bot has the specified permissions from the object provided, and will return an array with all the missing permissions

Firebase with angular : export selected fields only to excel from retrieved firebase with angular

There is a problem with my work. since Firebase's Web/JavaScript API always returns the full tree under the nodes that we request.
So in my case i retrieved all of existing fields from firebase including sensitive fields first and after that I want to export to excel selected fields only, not all of the fields that i got. the problem is, I always succeed exported all existing fields, including the sensitive fields.
Can I export selected field only and exclude the sensitive field? Below is my code:
I retrieve all of my fields include the data from firebase in my .ts file like this:
getData() {
this.dataLoading = true;
this.querySubscription = this._backendService.getDocs('report')
.subscribe(members => {
this.members = members;
this.dataSource = new MatTableDataSource(members);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
},
(error) => {
this.error = true;
this.errorMessage = error.message;
this.dataLoading = false;
},
() => { this.error = false; this.dataLoading = false; });
}
//export func
exportAsXLSX():void{
this._backendService.exportAsExcelFile(this.members, 'sample');
}
My Backend service Code :
getDocs(coll:string,filters?:any){
this.itemsCollection=this.afs.collection<any>(this.getCollectionURL(coll));
return this.itemsCollection.valueChanges();
}
getCollectionURL(filter){
return "ReportApp/fajar/"+filter;
}
//export func
public exportAsExcelFile(json: any[], excelFileName: string): void {
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(json);
const workbook: XLSX.WorkBook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] };
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
this.saveAsExcelFile(excelBuffer, excelFileName);
}
private saveAsExcelFile(buffer: any, fileName: string): void {
const data: Blob = new Blob([buffer], {type: EXCEL_TYPE});
FileSaver.saveAs(data, fileName + '_export_' + new Date().getTime() + EXCEL_EXTENSION);
}
as for reference im using code from here to exporting to excel :https://medium.com/#madhavmahesh/exporting-an-excel-file-in-angular-927756ac9857
as u can see I put all of my data into this.member variable and export em, But the result is that I exported all of em, i want to export selected fields only.
You will need to "trim down" the array of member data before you send it to your exportAsExcelFile() method. Your problem is that you are passing ALL of the member data to that export function. So the solution is to remove any sensitive information before you call the export function.
exportAsXLSX():void {
// TRIM DOWN ARRAY HERE
this._backendService.exportAsExcelFile(this.members, 'sample');
}
Since you didn't provide your member database structure, or details of what you consider sensitive information, I'll provide a generic example. You have an array of members... Most likely, you've made each "member" in the array into an object... so we need to loop over that array and delete the "sensitive" property of each member object.
As a precaution, since we don't want to delete the properties from the ACTUAL array, since arrays are reference-types, and since you might need those details elsewhere... let's make a copy of the array - a deep copy to ensure even nested objects are copied.
var newMemberArray = JSON.parse(JSON.stringify(this.members))
Then, we need to loop over that new array and delete our sensitive properties:
newMemberArray.forEach(function(m){
delete m.sensitivePropertyName1;
delete m.sensitivePropertyName2;
});
and pass that "sanitized" array to your export function... so putting all this together, something like:
exportAsXLSX():void {
var newMemberArray = JSON.parse(JSON.stringify(this.members))
newMemberArray.forEach(function(m){ delete m.sensitivePropertyName });
this._backendService.exportAsExcelFile(newMemberArray, 'sample');
}
*Disclaimer: untested code, for explanation purposes only

new data added to JSON keeps replacing previous

It seems like "notes = JSON.parse(fs.readFileSync("notes-data.json"))" line of my code is not working as it should...
When I add new notes it should add on to the array in the .json file, but it just replaces the previous note.
let addNote = (title, body) => {
let notes = [];
let note = {
title,
body
};
notes.push(note);
fs.writeFileSync("notes-data.json", JSON.stringify(notes));
notes = JSON.parse(fs.readFileSync("notes-data.json"))
};
Code Screenshot:
Thank you in advance
If you want to add to the file contents, then you should really read the content before doing anything else:
let addNote = (title, body) => {
let notes;
try {
notes = JSON.parse(fs.readFileSync("notes-data.json")); // <---
} catch(e) {
notes = [];
}
let note = {
title,
body
};
notes.push(note);
fs.writeFileSync("notes-data.json", JSON.stringify(notes));
};

Google Cloud Talent Solution fetch a job by requisitionId

I am wondering if it is possible to fetch a job by requisitionId in Google Cloud Talent Solution. requisitionId has to be unique across jobs so it seems like a natural candidate for looking a job up.
When a job is created the api returns a job name that can be used to look the job up:
You can retrieve the details of a previously inserted job by sending a GET request to the Cloud Talent Solution. The URI should include the previously inserted job name returned by the original create request, as a URL parameter.
I'd like to avoid storing these names if possible. In my view storing them adds unnecessary complexity since I already have a unique requisitionId. To be clear the API does not let you add jobs with a duplicate requisitionId:
Job projects/{my_app_id}/jobs/{google_assigned_id} already exists. Request ID for tracking: ... Related Job requisition ID: ...
So can I look up jobs by requisitionId?
I could parse the error message that's returned to get the job name..but that seems pretty brittle.
It turns out the list method takes requisitionId so for a full, read-create-update cycle we can do:
const listRequest = {
parent: `projects/${projectId}`,
'filter': `companyName="${companyName}" AND requisitionId="${requisitionId}"`
}
const listResult = await jobService.projects.jobs.list(listRequest)
const existingJobs = listResult.data.jobs || [];
let existingJob = null
if (existingJobs && existingJobs.length > 0) {
existingJob = existingJobs[0]
}
let googleJob
if (!existingJob) {
const createRequest = {
'parent': `projects/${projectId}`,
'resource': {
'job': {
companyName,
requisitionId,
title,
description,
applicationInfo: {
emails: ['email#example.com']
}
}
}
}
googleJob = await jobService.projects.jobs.create(createRequest)
.then(result => result)
.catch(resp => {
console.error("ERROR")
console.error(resp)
})
} else {
const patchRequest = {
'name': existingJob.name,
'resource': {
'job': {
companyName,
requisitionId,
title,
description,
applicationInfo: {
emails: ['email#example.com']
}
}
}
}
googleJob = await jobService.projects.jobs.patch(patchRequest)
.then(result => result)
.catch(resp => {
console.error("ERROR")
console.error(resp)
})
}
Docs: https://cloud.google.com/talent-solution/job-search/docs/reference/rest/v3/projects.jobs/list?authuser=0&hl=de
Notes:
The double quotes in the filter parameter are important. It will not accept single quotes and will give a cryptic error message.
The patch request cannot take a parent parameter even though everything else requires a parent parameter...
one can add it as custom attribute:
Map<String, CustomAttribute> attributes = new HashMap<>();
attributes
.put("requisitionId", new CustomAttribute().setStringValue(requisitionId)
.setFilterable(true));
Job job = new Job()
...
.setCustomAttributes(attributes);
Job jobCreated = createJob(job);
String jobName = jobCreated.getName();
and then search for requisitionId with a custom attribute filter:
JobQuery jobQuery = new JobQuery().setCustomAttributeFilter(filter);
this is a little redundant, but JobQuery has no method .setRequisitionId().
here's the documentation.

Resources