Adding a media field when creating a new entry - contentful-management

I've searched around and looked at all the SDK docs and on Contentful's API docs I am having difficulty understanding how to add a media field with a link to an asset when creating a new entry. I can successfully create the other fields, but a media field should be an object but I am not sure exactly how to format that so Contentful will accept it.
const videoAsset = yield client.getAsset(assetID)
fields = {
title: {
"en-US": 'Title' //works
},
description: {
"en-US": 'Description' //works
},
video: {
"en-US": //contenful api wants an object, what does this object look like?
//i have a published asset in videoAsset returned by client.getAsset()
},
team: {
"en-US": 'Community' //works
},
}
const entryCreated = yield space.createEntry(action.payload.contentType, {
fields: fields
})
When I I say "works" I mean that I can successfully create an entry that appears in Contentful space.

I got it!
This person wasn't doing exactly the same thing but the answer in terms of formatting was here:
https://github.com/contentful/contentful-management.js/issues/57
Basically the field should look like this:
const videoAsset = yield client.getAsset(assetID)
fields = {
title: {
"en-US": 'Title' //works
},
description: {
"en-US": 'Description' //works
},
video: {
"en-US": {
sys: {
type: "Link", linkType: "Asset", id: assetID
}
}
}, //this formatting works!
team: {
"en-US": 'Community' //works
},
}
const entryCreated = yield space.createEntry(action.payload.contentType, {
fields: fields
})

Related

How can I display multiple ResponseDTOs' schemas in Swagger/NestJS?

I have this route which can return one of these two different DTOs:
#Get()
#ApiQuery({ name: 'legacy', description: "'Y' to get houses legacy" })
async findAllHouses(
#Query('legacy') legacy: string,
): Promise<HousesDto[] | HousesLegacyDto[]> {
...
}
I want to display both of these ResponseDTOs in swagger.
I've tried this decorator:
#ApiOkResponse({
schema: { oneOf: refs(HousesDto, HousesLegacyDto) },
})
// OR
#ApiOkResponse({
schema: {
oneOf: [
{ $ref: getSchemaPath(HousesDto) },
{ $ref: getSchemaPath(HousesLegacyDto) },
],
},
})
with #ApiExtraModels() on top of DTO classes and #ApiProperty() on each properties.
But I still get empty objects in Swagger and I suppose it would not have even taken array types in consideration.
How can I display both of these schemas properly?
Seems to me like a lot of very obscure solutions have been posted here and there, so I will try to clarify what needs to be done.
You have two DTOs:
export class SomeStatusDto {
#ApiProperty({
description: 'Id',
example: 1,
})
#IsNumber()
id: number;
#ApiProperty({
description: 'Status',
example: 'in_progress',
})
#IsString()
status: string;
}
export class ErrorStatusDto {
#ApiProperty({
description: 'Id',
example: 1,
})
#IsNumber()
id: number;
#ApiProperty({
description: 'Error',
example: 'Some error string',
})
#IsString()
error: string;
}
Then you have your controller:
#UseGuards(AccountTypesGuard)
#ApiOperation({ summary: 'Get status of...' })
#Get('status')
#ApiExtraModels(SomeStatusDto, ErrorStatusDto)
#ApiOkResponse({
schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
})
async getPullStatus(
#Request() req,
#Param('id', ParseIntPipe) someId: number,
): Promise<SomeStatusDto | ErrorStatusDto> {
// check if someId belongs to user
const idBelongsToUser = await this.myService.validateSomeId(
req.user.id,
someId,
);
if (!idBelongsToUser) {
throw new ForbiddenException(
`SomeId does not belong to user (someId=${someId}, userId=${req.user.id})`,
);
}
const key = `status-${someId}`;
const response = await this.redisService.getByKey(key);
return response ? response : {};
}
Note the solution below. You need to reference the DTOs as #ApiExtraModels() and then you can add them as anyOf: refs(...) in your schema.
#ApiExtraModels(SomeStatusDto, ErrorStatusDto)
#ApiOkResponse({
schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
})
Hope this helps somebody :)
so I encountered a similar issue and this is how you could get the output shown in the image above.
Using the #ApiResponse decorator you could set the two responses using the examples property, try the code sample below
#ApiResponse({
status: 200,
description: 'Successful response',
content: {
'application/json': {
examples: {
HousesDto: { value: HousesDto },
HousesLegacyDto: { value: HousesLegacyDto },
},
},
},
})

Loopback POST array of entry?

I want to insert 10 entries with one query against 10 queries.
I read that it's possible to do it by sending an array like this :
But I get this error:
Do I need to set something? I don't know what to do at all.
Repo with a sample : https://github.com/mathias22osterhagen22/loopback-array-post-sample
Edit:
people-model.ts:
import {Entity, model, property} from '#loopback/repository';
#model()
export class People extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'string',
required: true,
})
name: string;
constructor(data?: Partial<People>) {
super(data);
}
}
export interface PeopleRelations {
// describe navigational properties here
}
export type PeopleWithRelations = People & PeopleRelations;
The problem with your code was :
"name": "ValidationError", "message": "The People instance is not
valid. Details: 0 is not defined in the model (value: undefined);
1 is not defined in the model (value: undefined); name can't be
blank (value: undefined).",
Here in above as in your #requestBody schema, you are applying to insert a single object property, where as in your body are sending the array of [people] object.
As you can see in your people.model.ts you have declared property name to be required, so system finds for the property "name", which obviously not available in the given array of object as primary node.
As you are passing index array, so its obvious error that you don't have any property named 0 or 1, so it throws error.
The below is the code hat you should apply to get insert the multiple, items of the type.
#post('/peoples', {
responses: {
'200': {
description: 'People model instance',
content: {
'application/json': {
schema: getModelSchemaRef(People)
}
},
},
},
})
async create(
#requestBody({
content: {
'application/json': {
schema: {
type: 'array',
items: getModelSchemaRef(People, {
title: 'NewPeople',
exclude: ['id'],
}),
}
},
},
})
people: [Omit<People, 'id'>]
): Promise<{}> {
people.forEach(item => this.peopleRepository.create(item))
return people;
}
You can also use this below
Promise<People[]> {
return await this.peopleRepository.createAll(people)
}
You can pass the array of your people model by modifying the request body.If you need more help you can leave comment.
I think you have a clear solution now. "Happy Loopbacking :)"

Is there a way to replace URL Link of Text in Google Docs API?

I started exploring Google Docs API in Python. It does pretty much everything I want it to do except for one thing.
I can replace the text of a document but I can't change the value of the hyperlinks.
Meaning if a link looks like this : a link, I can change the value of the text a link but not the target URL.
I've been going through the documentation but I can't find anything about it. Could it be a missing feature or am I missing the way to do that?
You can modify the hyperlink using UpdateTextStyleRequest of the batchupdate method in Google Docs API. At this time, please set the property of Link of TextStyle.
Endpoint
POST https://docs.googleapis.com/v1/documents/{file ID}:batchUpdate
Request body:
{
"requests": [
{
"updateTextStyle": {
"textStyle": {
"link": {
"url": "https://sampleUrl" # Please set the modified URL here.
}
},
"range": {
"startIndex": 1,
"endIndex": 2
},
"fields": "link"
}
}
]
}
Note:
From your question, I could understand that you have already used Google Docs API and you can modify the text of the link text. I think that you can modify the link using above request body and the script you have.
References:
UpdateTextStyleRequest
TextStyle
Link
If this was not useful for your situation, I apologize.
Edit:
You want to retrieve the text with the hyperlink.
From your reply comment, I could understand like above. When my understanding is correct, you can retrieve it using documents.get method. In this case, when fields is used, the response become to easily read.
Endpoint:
GET https://docs.googleapis.com/v1/documents/{file ID}?fields=body(content(paragraph(elements(endIndex%2CstartIndex%2CtextRun(content%2CtextStyle%2Flink%2Furl)))))
In this endpoint, body(content(paragraph(elements(endIndex,startIndex,textRun(content,textStyle/link/url))))) is used as fields.
Sample response:
For example, when the following texts are put in a Google Document and def has a hyperlink,
abc
def
The response is as follows. From the following result, you can retrieve the position of text with the hyperlink can be retrieved. Using this, you can modify the hyperlink.
{
"body": {
"content": [
{},
{
"paragraph": {
"elements": [
{
"startIndex": 1,
"endIndex": 5,
"textRun": {
"content": "abc\n",
"textStyle": {}
}
}
]
}
},
{
"paragraph": {
"elements": [
{
"startIndex": 5,
"endIndex": 8,
"textRun": {
"content": "def",
"textStyle": {
"link": {
"url": "https://sample/"
}
}
}
},
{
"startIndex": 8,
"endIndex": 9,
"textRun": {
"content": "\n",
"textStyle": {}
}
}
]
}
}
]
}
}
Reference:
documents.get
batchUpdate requires to know position of text, we can get document with all content and find positions of links
In my case I implement it as:
Copy template to new place with final name
Replace link texts and other parts of text
Get document
Find links positions in doc
Update link URLs
Here example in nodejs
const {google, docs_v1} = require('googleapis');
async function replaceInDoc(doc) {
let documentId = 'some doc id'
let auth = 'auth value for user'
let linkNewUrl = 'https://github.com/googleapis/google-api-nodejs-client'
google.options({auth: auth})
var docs = new docs_v1.Docs({}, google)
// document should have link with http://repo-url.com text, we will update it
var requests = [
{
replaceAllText: {
containsText: {
text: 'http://repo-url.com',
matchCase: true,
},
replaceText: linkNewUrl,
},
}
]
var updateRes = await docs.documents.batchUpdate({
documentId: documentId,
resource: {
requests: requests,
},
});
var docInfo = await docs.documents.get({documentId: documentId})
var linkPos = findLinksInDoc(docInfo)
// set new url to link by position of link in the document
var requests = [
{
updateTextStyle: {
textStyle: {
link: {
url: linkNewUrl
}
},
range: {
startIndex: linkPos[linkNewUrl][0],
endIndex: linkPos[linkNewUrl][1]
},
fields: "link"
}
}
]
var updateRes = await docs.documents.batchUpdate({
documentId: documentId,
resource: {
requests: requests,
},
});
}
// returns hash as { 'http://example.com': [startPosition, endPosition] }
function findLinksInDoc(doc) {
var links = {}
doc.data.body.content.forEach(section => {
if (section.paragraph) {
section.paragraph.elements.forEach(element => {
if (element.textRun && element.textRun.textStyle.link) {
links[element.textRun.content] = [element.startIndex, element.endIndex]
}
})
}
})
return links
}

Update Kendo Grid based On Search Form Post

I've been doing alot of searching but haven't found a clear answer for this. I have a set up textboxes that and a submit button and a Kendo UI grid. I want to post the data to the grid's datasource so that it will return the results based on the criteria. I am not using the MVC wrappers.
EDIT:
I've gotten closer but I can't seem to get the datasource to send the post data when I click submit. I've debugged and in my $("#fmSearch").submit it is hitting the jquery plugin and I've confirmed that it is converting the form data to JSON properly, but it seems as though it it not sending the updated information to the server so that the Action can read it.
Javascript
var dsGalleryItem = new kendo.data.DataSource({
transport: {
read: {
url: '#Url.Content("~/Intranet/GalleryItem/SearchGalleryItems")',
type: "POST",
data: $("#fmSearch").serializeFormToJSON(),
cache: false
}
},
schema: {
model: {
id: "galleryItemID",
fields: {
galleryItemID: {
nullable: true
},
imageName: {},
collectionName: {},
categoryName: {},
lastUpdatedOn: { type: "date" }
}
}
}
});
var gvResults = $("#gvResults").kendoGrid({
autoBind:false,
columns: [{
field: "imageName",
title: "Item Name",
template: "<a href='#Url.Content("~/Intranet/GalleryItem/Details/")#=galleryItemID#'> #=imageName#</a>"
}, {
field: "collectionName",
title: "Collection"
}, {
field: "categoryName",
title: "Category"
}, {
field: "lastUpdatedOn",
title: "Last Updated",
format: "{0:M/d/yyyy}"
}
],
selectable: "row",
change: onRowSelect,
dataSource: dsGalleryItem
});
$("#fmSearch").submit(
function (event) {
event.preventDefault();
dsGalleryItem.read({ data: $("#fmSearch").serializeFormToJSON() });
});
MVC Action
[HttpPost]
public JsonResult SearchGalleryItems(string keyword, int? category, int? collection, DateTime? startDate, DateTime? endDate)
{
var galleryItemList = (from g in db.GalleryItems
//where g.imageName.Contains(keyword)
select new GalleryItemViewModel
{
galleryItemID = g.galleryItemID,
imageName = g.imageName,
collectionName = g.collection.collectionName,
categoryName = g.category.categoryName,
lastUpdatedOn = g.lastUpdatedOn
});
var galleryItemCount = Json(galleryItemList.ToList());
return Json(galleryItemList.ToList()); ;
}
The action is not setup to retrieve different data right now I just need to know how to connect the form to the grid.
Found the problem. I had this:
dsGalleryItem.read({ data: $("#fmSearch").serializeFormToJSON() });
It needed to be this:
dsGalleryItem.read($("#fmSearch").serializeFormToJSON());

How to initialize the selection for rails-select2 in BackboneForms schema?

The project uses marionette-rails, backbone-on-rails, select2-rails and this port to BackboneForms to provide a multiselect form field. The select options are available to the user. They are retrieved from the collection containing the total list of options:
MyApp.module("Products", function(Products, App, Backbone, Marionette, $, _) {
Products.CustomFormView = Products.CustomView.extend({
initialize: function(options) {
this.model.set("type", "Product");
Products.EntryView.prototype.initialize.apply(this, arguments);
},
schemata: function() {
var products = this.collection.byType("Product");
var productTypes = products.map(function(product){
return {
val: product.id,
label: product.get("name")
};
});
return {
productBasics: {
name: {
type: "Text",
title: "Name",
editorAttrs: {
maxLength: 60,
}
},
type: {
type: 'Select2',
title: "Product type",
options: {
values: productTypes,
value: [3, 5],
initSelection: function (element, callback) {
var data = [];
$(element.val().split(",")).each(function () {
data.push({id: this, text: this});
});
callback(data);
}
},
editorAttrs: {
'multiple': 'multiple'
}
}
}
};
}
});
});
Do I initialize the value correctly in options.value? How comes initSelection is never called? I copied the function from the documentation - it might be incomplete for my case. None of the products with the IDs 3 and 5 is displayed as the selection.
initSelection is only used when data is loaded asynchronously. My understanding is that there is no way of specifying the selection upon initialization if you are using an array as the data source for a Select2 control.
The best way of initializing the selection is by using setValue after the form is created. Here is a simplified example based on the code in your example.
var ProductForm = Backbone.Form.extend({
schema: {
type: {
type: 'Select2',
title: "Product type",
options: {
values: productTypes,
},
editorAttrs: {
'multiple': 'multiple'
}
}
});
var form = new ProductForm({
model: new Product()
}).render();
form.setValue("type", [3, 5]);
You can use value function (http://ivaynberg.github.io/select2/#documentation) in setValue. I personally recomend you to use this backbonme-forms plugin: https://gist.github.com/powmedia/5161061
There is a thread about custom editors: https://github.com/powmedia/backbone-forms/issues/144

Resources