How to update djangocms-blog post extensions fields position? - django-cms

I have some post extensions adding new fields in my Posts objects.
I created the migration, launched my website, and I thought that maybe customizing the fieldsets would allow me to customize the position of the post extensions fieldset too.
That didn't seems to be the case. I created a new SmallIntegerField named my_new_field in a PostExtension class that I registered using blog_admin.register_extension(PostExtensionInline) (I also created the PostExtensionInline class by following the doc).
I added a breakpoint in my update_fields function that I'm using to update the order of the fields of my posts (see this SO question and its answer for more infos on this), and I can't find any mention to my_new_field in the fgets arg:
Quit the server with CONTROL-C.
> /home/me/my-test-app/my_test_app/update_fields.py(3)update_fields()
-> return fsets
(Pdb) l
1 def update_fields(fsets, request, obj):
2 breakpoint()
3 -> return fsets
[EOF]
(Pdb) fsets
[(None, {'fields': ['title', 'subtitle', 'slug', 'publish', 'categories', 'abstract', 'sites', 'author']}), ('Info', {'fields': [['tags', 'related'], ['date_published', 'date_published_end', 'date_featured'], 'app_config', 'enable_comments'], 'classes': ('collapse',)}), ('Images', {'fields': [['main_image', 'main_image_thumbnail', 'main_image_full']], 'classes': ('collapse',)}), ('SEO', {'fields': [['meta_description', 'meta_title', 'meta_keywords']], 'classes': ('collapse',)})]
How can I update my field position? (see edit below)
edit: I can't think of a way to tweak the order of the post extension fields. But I realized that my real problem (yeah yeah that's a case of XYproblem) is that I want conditional inline (only include the post extension for a certain apphook that's using a defined BlogConfig instance.
How to conditionally add the inline post extension form/fields to my admin create form based on the BlogConfig instance?

So I figured it out (and it's not pretty, but it works).
I added those lines in my admin.py:
# replace PostAdmin get_inlines function in order to hide event_date on regular blog posts
from djangocms_blog.admin import PostAdmin
from .misc import get_inline_instances as patched_get_inline_instances
PostAdmin.get_inline_instances = patched_get_inline_instances
And here's my code on misc.py:
def get_inline_instances(self, request, obj=None):
from djangocms_blog.cms_appconfig import BlogConfig
from djangocms_blog.admin import PostAdmin
from json import loads
inline_instances = super(PostAdmin, self).get_inline_instances(request, obj)
if "app_config" in request.GET:
# get blog config instance from request
blog_config = BlogConfig.objects.filter(pk=request.GET["app_config"])
# get config from saved json
config = loads(blog_config.values()[0]["app_data"])
# get template_prefix from config
if config:
template_prefix = config['config']['template_prefix']
if template_prefix == "djangocms_blog_agenda":
return inline_instances
return []
I used the template_prefix value in a BlogConfig instance of djangocms_blog to update the code based on the request:
If we have "djangocms_blog_agenda" in the template_prefix, then return the inline instances.
If we don't have this (default BlogConfig, another BlogConfig that do not need my current post extension fields), return an empty list.
The result can be viewed here:
Blog posts list screenshot, we can see that the articles are displayed by most recent "published date" first.
We can select our blog config after a click on "Blog > Add Post...".
Agenda post creation screenshot, we can see that there's a post extension named "event date" (not present in Blog post creation screenshot).
Agenda list screenshot, we can see that the "events" are displayed by nearest future "event date" date.

Related

How to extract params from received link in react native firebase dynamiclink?

I tried to migrate from react navigation deeplinks to firebase dynamic linking using this library (react-native-firebase).
I have set up everthing and links are being generated and received on the app. However, is there any way to extract the params sent in the link properly using this library?. Currenty this is my code for handling received link:
handleDynamicLink = () => {
firebase
.links()
.getInitialLink()
.then((url) => {
console.tron.log('link is ', url);
})
.catch((error) => {
console.tron.log(error);
});
};
The url received is
https://links.dev.customdomain.in/?link=products%2F1122
I want to extract the product id 1122 from the url. The only way for me right now is to parse the string and manually extract the relevant params. Unlike in react navigation deeplinks where I used to specify the path, like
Product: {
screen: Product,
path: 'customdomain/products/:slug',
},
Where the slug or id data used to pass as navigation param in the respective screen. Am I missing something? How can I pass mutliple params this way?
Point 2 in this link here says:
The response contains the URL string only.
This means that the firebase.links().getInitialLink() method does not return query parameters, at least as at the time of writing this (v5.5.5). To add your paramaters, you should use a URL with your query param as part of the URL. What I mean is this
Use https://links.dev.customdomain.in/link/products/1122
and use Regex to extract the product id which is of interest to you. This is what works for me and I hope it helps.

Orchard CMS Projection Query String With Taxonomies

I have created a Content Type called "Products" which has a few fields, 2 of which are Taxonomy Fields (Product Type and Material)
Product Types: Cable cleats, Cable clamps, Pole cleats, Cable core
Material: Stainless steel, Aluminium, Galvanised steel
I have a product listing and would like to filter it using the query string, over both taxonomies for example
List all products with product type of Cable cleats and material of Stainless steel
~/products?product-type[]=Cable cleats&material[]=Stainless steel
List all products with product type of Cable cleats or Pole cleats and material of Stainless steel
~/products?product-type[]=Cable cleats&product-type[]=Pole cleats&material[]=Stainless steel
(guessing it will be IDs used not the full text string for all queries)
Is there a way in Orchard to do this? or would it need a custom Module?
Any help would be much appreciated
Many thanks
Anto
Many projection filters have parameters where you can use tokens. To use the query string, you would use the QueryString token, like this: {QueryString:product-type}. Unfortunately, the taxonomy term filter does not currently work with tokens. It shouldn't be too hard to add that possibility however. Most of the code is already there.
Quite an old question, but because it was referenced here, i give here a copy of my answer...
Note: Tried with a recent Orchard dev branch.
Here, for testing, i've done some changes directly in TermsFilter.cs and TermsFilterForms.cs, but based on this example, you will be able to write your own IFilterProvider and IFormProvider...
So, in TermsFilterForms.cs, in the Describe() method where the form is defined, try to add this:
...
),
_ProductType: Shape.TextBox(
Id: "product-type", Name: "ProductType",
Title: T("Product Type"),
Classes: new[] { "text medium", "tokenized" },
Description: T("Enter the product type.")
)
);
...
Then, when editing your filter, you will see a new input field that can be tokenized and where e.g you can put:
{Request.QueryString:product-type}
Then, in TermsFilter.cs, you can inject a tokenizer:
...
private readonly ITokenizer _tokenizer;
public TermsFilter(ITaxonomyService taxonomyService, ITokenizer tokenizer) {
_taxonomyService = taxonomyService;
T = NullLocalizer.Instance;
_tokenizer = tokenizer;
}
...
Then in the ApplyFilter(dynamic contex) method, you can tokenize your product-type field like this:
var termName = _tokenizer.Replace((string)context.State.ProductType, null);
Here, for testing, in the query string product-type parameter, i expect only one value (not an array) that is a term name (not an id). But you can change the code according to your needs...
Then, by using the taxonomy service, you can do things like that:
var taxoPart = _taxonomyService.GetTaxonomyByName("Product Type");
var termPart = _taxonomyService.GetTermByName(taxoPart.Id, termName);
And then you can use e.g the termPart.Id to update the context.Query (see in the code)...
Best

Include "Change Note" when creating content from InvokeFactory

I am creating a content item from a PloneFormGen Form Custom Script Adapter using invokeFactory. Everything is working fine so far, however we want to start generating a comment to be included in the create action, for the history of the item. The comment itself will be generated using fields from the form and some preset text.
Is this something that would be possible from PFG?
The content type is a custom type, and it is versionable. Using Plone 4.3.2, PFG 1.7.14
EDIT
My current code:
from Products.CMFPlone.utils import normalizeString
portal_root = context.portal_url.getPortalObject()
target = portal_root['first-folder']['my-folder']
form = request.form
title = "My Title: "+form['title-1']
id = normalizeString(title)
id = id+"_"+str(DateTime().millis())
target.invokeFactory(
"MyCustomType",
id=id,
title=title,
text=form['comments'],
relatedItems=form['uid']
)
I have tried using keys like comments, comment, message, and even cmfeditions_version_comment within the target.invokeFactory arguments. No luck so far.
I'm not sure if that's possible in a custom script adapter.
The action of you first entry is None. The history automatically shows Create if the action is None. This is implemented here (plone.app.layout.viewlets.content)
# On a default Plone site you got the following
>>> item.workflow_history
{'simple_publication_workflow': ({'action': None, 'review_state': 'private', 'actor': 'admin', 'comments': '', 'time': DateTime('2014/10/02 08:08:53.659345 GMT+2')},)}
Key of the the dict is the workflow id and the value is a tuple of all entries.
So you can manipulate the entry like you want. But I don't know if this is possible with restricted python (custom script adapter can only use restricted python).
But you could also add a new entry, by extending you script with:
...
new_object = target.get(id)
workflow_tool = getToolByName(new_object, 'portal_workflow')
workflows = workflow_tool.getWorkflowsFor(new_object)
if not workflows:
return
workflow_id = workflows[0].id # Grap first workflow, if you have more, take the the one you need
review_state = workflow_tool.getInfoFor(new_object, 'review_state', None)
history_entry = {
'action' : action, # Your action
'review_state' : review_state,
'comments' : comment, # Your comment
'actor' : actor, # Probably you could get the logged in user
'time' : time,
}
workflow_tool.setStatusOf(workflow_id, context, history_entry)

Meteor: How do I adjust iron router return data based on search query?

I have an app where users can take notes.
In the html page I iterate over each note like so:
<div id="notes-container" class="notes">
{{each notes}}
{{> note}}
{{/each}}
</div>
and in my router file I return the data like so:
#route: 'notes'.
path: '/notes/:_id',
data: ->
notes = Notes.find
threadId: #params._id
trash:
$exists: false
,
sort:
date: -1
All is typical meteor stuff so far. But I am confused now about how to adjust the data that is iterated on in the html page.
Each notes has a array field for tags like tags: ['apple' ,'red', 'green']
What if the user wants to return all notes with the tag 'red'. So there is a input box on the site the user enters a tag and presses enter.
How can I adjust the data that is sent to the page so queries mongodb to return all notes with tag red? I know how to write the query I am not sure how to set this up though in meteor.
One way I tried to do it is called the same route with query paramters like: '/notes/326363235474?tags=apple'
And in iron router I can look for query parameters and return the right set of documents but then when I call the original route again to clear the search, it does not load all of the original documents again.
Any suggestion on how I can set this up? Thanks
the data function simply needs to return the data you want available within the template context, if I'll define this function to a certain route:
data: ->
return Drawing.findOne
_id: window._drawing_id
I will have that data in my "this" object when proccessing that template.

Drupal Views: Programmatically alter a View and execute to array

Essentially I have a View called 'promo' that's built on a Nodequeue. It is being restricted to 1 row, and order by Global:Random
The view itself is being used for a block on the site.
Additionally, the view same view is being for a node reference field 'field_promo'.
What I would like to do is to obtain the 2 most recent rows from the promo view, and use these as the default values for field_promo.
What this requires is that I:
load the view
remove the global:random sort
add a created sort
change pager to display 2 rows instead of 1
execute the view
...
Since writing all this and making sure I'm not an idiot, I've gathered together the solution which I may as well post below since it took me so long to find it! (will post solution after 8 hours, I'll give points if you crack the answer before I get to post :P)
Here is the solution I came up with:
$view = views_get_view('promo_feature');
$view->init_display();
$view->preview=TRUE;
$view->is_cacheable = FALSE;
$view->display_handler->set_option('items_per_page',2);
$view->set_item('default', 'sort', 'random', NULL);
$view->add_item('default', 'sort', 'node', 'created',array('order' => 'DESC'));
$view->pre_execute();
$output = $view->display_handler->preview();
$view->post_execute();
$return=array();
foreach($view->result as $row){
$return[]=array('nid' => $row->nid);
}
return($return);
$view->set_item($display,$type,$id,NULL) removes that item from the view
I suspect there's a more refined version of this code, however it took me so long to get there I'm afraid to touch it in case I destroy it :)

Resources