What's the best (or simplest) way to delete portlets site-wide in plone 4.x?
It depends. If you have a small amount of local assigned portlets I suggest the manual way. If you have a complex assignment of local portlets you could take this way:
1- create a browser view linked to the site root
2- add this:
from Products.Five import BrowserView
from Products.CMFCore.utils import getToolByName
from zope.component import getMultiAdapter
from plone.portlets.interfaces import IPortletManager
from plone.portlets.interfaces import IPortletAssignmentMapping
from plone.portlets.interfaces import ILocalPortletAssignable
class MyView(BrowserView):
def __call__(self):
ctool = getToolByName(self.context, 'portal_catalog')
all_brains = ctool.searchResults()
for i in all_brains:
obj = i.getObject()
if not ILocalPortletAssignable.providedBy(obj):
continue
for manager_name in ('plone.leftcolumn','plone.rightcolumn'):
manager = getUtility(IPortletManager, name=manager_name)
assignment_mapping = getMultiAdapter((obj, manager),
IPortletAssignmentMapping)
for i in assignment_mapping.keys():
del assignment_mapping['assignment_mapping']
Usually retrieving all objects is not a good thing, so you should evaluate carefully the amount of contents and local portlers. That said, this way is a bit aggressive but it will do the job.
I think you made a small typo:
del assignment_mapping['assignment_mapping']
should be:
del assignment_mapping[i]
Related
My project is a react project.
My website is a mutilanguage website, when I change the web language. moment.locale(lang) not working.
My code is:
const startDate = moment.utc(start).locale(lang);
const endDate = moment.utc(end).locale(lang);
whatever I set lang I check the startDate.locale() always is 'en'
startDate.format('ll') result always is English.
If the project was created using create-react-app, moment locales were probably excluded by default.
This is now documented in the "Moment.js locales are missing" section of create-react-app's troubleshooting guide.
Solution: explicitly import locales in addition to 'moment':
import moment from 'moment';
import 'moment/locale/fr';
import 'moment/locale/es';
// etc. as required
According to this github issue, from 2022 on or so, it has to be imported like so:
import moment from 'moment';
import 'moment/dist/locale/de';
moment.locale('de');
if this doesn't work, try this change:
import moment from 'moment/dist/moment';
I think if you do
import 'moment/min/locales'
Instead of individual import of each locale.
In my case it resolve my problem
I found the solution here: https://stackoverflow.com/a/55334751/8318855
You should use the moment.updateLocale function
i am using wtforms with flask framework. when i use DateTimeField i add format parameter.
But datetime format is coming from user which is logged in
forms.py
from flask import g
from wtforms import *
import wtforms.validators as v
from flask.ext.babel import lazy_gettext as _
from flask.ext.babel import npgettext as _n
from app.app import app
from app.base_forms import *
from app.modules.post.models import *
class PostForm(BaseForm):
post_date = DateTimeField("Post Date", format = app.config.get("DATETIME_FORMAT"), validators =[v.Required(message=_("Post date is required"))] )
i set value of app.config.get("DATETIME_FORMAT") on before request
#app.before_request
def before_request():
if g.user.language == "tr"
app.config["DATETIME_FORMAT"] = "%d.%m.%Y %H:%M"
else:
app.config["DATETIME_FORMAT"] = "%m-%d-%Y %H:%M"
my application structure
/app
/modules
/post
/controllers.py
/forms.py
/models.py
/app.py
/run.py
content of /app/app.py
from flask import Flask, url_for, g, request, redirect, render_template
app = Flask(__name__)
app.config.from_object('app.config.config.ConfigDevelopment')
# Import Modules
from modules.post.controllers.admin import module as modulePostAdmin
app.register_blueprint(modulePostAdmin)
# other codes here
#app.before_request
def before_request():
if g.user.language == "tr"
app.config["DATETIME_FORMAT"] = "%d.%m.%Y %H:%M"
else:
app.config["DATETIME_FORMAT"] = "%m-%d-%Y %H:%M"
content of /run.py
from app.app import app
app.run(host='localhost', port=8080, debug=True)
when i start app it throws that error "KeyError: 'DATETIME_FORMAT'". i think forms.py load before request so it throws keyError.
What is the correct way for solving this problem.
Oh, I see your problem, the date format you want is changing on a per-request basis. app.config won't help you with this.
Here's what I would do:
from flask import g
from wtforms import DateTimeField
class I18NDateTimeField(DateTimeField):
def __init__(self, label=None, validators=None, format=None, **kwargs):
if g.user.language == "tr"
format = "%d.%m.%Y %H:%M"
else:
format = "%m-%d-%Y %H:%M"
super(I18NDateTimeField, self).__init__(label=label, validators=validators, format=format, **kwargs)
class PostForm(Form):
post_date = I18NDateTimeField("Post Date", validators =[v.Required(message=_("Post date is required"))] )
Background
You're (mostly) right, before_request hasn't been called yet. That said, the form definition doesn't happen in a request context at all, it happens when the app is imported, long before any requests arrive, and it won't happen more than once.
However, the form and its fields will be instantiated again for every request, and that's why this works. It's ok to modify self.format here since this field object is only being used for this request anyway.
Update 2:
I edited my answer to subclass Form instead of BaseForm. BaseForm is part of WTForms's low-level API; they say not to use it unless you're sure you need to. I also put that internationalization logic in the constructor rather than process_formdata (thanks to mattupstate from #pocoo for the idea).
I think it's a little clearer that way, and inspecting the field in the debugger will make more sense. Now, the way the code is written, you'd expect the field to be instantiated as a class attribute when the form is defined, which means that wouldn't work and this code wouldn't be thread-safe. But due to some metaclass trickery, the field is actually instantiated as an instance attribute when the form is instantiated. Note that that metaclass trickery doesn't work properly if you use BaseForm, which is another reason to avoid BaseForm.
Update 3:
Sorry, just talked with you on IRC and found out you wrote your own BaseForm that subclasses Form. That's perfectly fine :)
I'm not sure if it would be configured correctly when you do that. Your app.config is probably not on the app because of the structure of how you made it. Did you make it like app = Flask(__name__) and import that?
You could probably solve it by using the app factory pattern
# app/__init__.py
def create_app():
app = Flask(__name__)
app.config.from_object('app.settings.default')
from app.yourforms import bp
app.register_blueprint(bp)
return app
You can make a blueprint in a separate file like so:
# yourforms/__init__.py
from flask import Blueprint
bp = Blueprint('forms', __name__)
from . import views
Then in your views.py file in that same directory, use the blueprint
from flask import current_app
from . import bp
from .forms import PostForm
#bp.before_app_request
def set_datetime_format():
# your code
# access app's config with current_app.config.get('YOURKEY')
then you just need to tweek your runfile a little bit, to do this:
if __name__ == '__main__':
app = create_app()
app.run()
I'm attempting to make an add-on that, among other things, adds another option to the personal preferences page. I've tried to piece together how to do this properly from various guides on loosely related topics, but I've had no luck. I'm just getting into Plone development, and a lot of this is somewhat foreign to me, so please be kind :)
I'm doing all this in Plone 4.3
When I have the add-on enabled on the site, it doesn't give me any errors, but the extra field isn't included on the preferences page.
So far, I've got something like this, ignore the odd naming scheme. Again, this was pieced together from other guides, and I wanted to get it working before I refactored.
userdataschema.py
from plone.app.users.browser.personalpreferences import IPersonalPreferences
from zope.interface import Interface
from zope import schema
class IEnhancedUserDataSchema(IPersonalPreferences):
""" Use all the fields from the default user data schema, and add various
extra fields.
"""
buttonsEnabled = schema.Bool(title=u'Transition button widget.',
default=True,
description=u'Uncheck to remove the transition button box from ALL pages.',
required=False
)
adapter.py:
from plone.app.users.browser.personalpreferences import PersonalPreferencesPanelAdapter
from app.statebuttons.userdataschema import IEnhancedUserDataSchema
from zope.interface import implements
class EnhancedUserDataPanelAdapter(PersonalPreferencesPanelAdapter):
"""
"""
implements(IEnhancedUserDataSchema)
def get_buttonEnabled(self):
return self.context.getProperty('buttonsEnabled', '')
def set_buttonsEnabled(self, value):
return self.context.setMemberProperties({'buttonsEnabled': value})
buttonsEnabled = property(get_buttonEnabled, set_buttonsEnabled)
overrides.zcml:
<configure
xmlns="http://namespaces.zope.org/zope"
i18n_domain="collective.examples.userdata">
<adapter
provides=".userdataschema.IEnhancedUserDataSchema"
for="Products.CMFCore.interfaces.ISiteRoot"
factory=".adapter.EnhancedUserDataPanelAdapter"
/>
</configure>
If anyone could give me some input on what I'm doing wrong, that would be awesome. If I'm way off the mark, I'd appreciate some input on where to go next.
You can make your new field show up on ##personal-preferences by adding this to your existing code:
browser/configure.zcml
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser">
<browser:page
for="plone.app.layout.navigation.interfaces.INavigationRoot"
name="personal-preferences"
class=".personalpreferences.CustomPersonalPreferencesPanel"
permission="cmf.SetOwnProperties"
layer="..interfaces.IAppThemeLayer"
/>
</configure>
browser/personalpreferences.py
from plone.app.users.browser.personalpreferences import PersonalPreferencesPanel
from plone.app.users.browser.personalpreferences import LanguageWidget
from plone.app.users.browser.personalpreferences import WysiwygEditorWidget
from zope.formlib import form
from app.statebuttons.userdataschema import IEnhancedUserDataSchema
class CustomPersonalPreferencesPanel(PersonalPreferencesPanel):
form_fields = form.FormFields(IEnhancedUserDataSchema)
# Apply same widget overrides as in the base class
form_fields['language'].custom_widget = LanguageWidget
form_fields['wysiwyg_editor'].custom_widget = WysiwygEditorWidget
Note that you'll need a browser layer IAppThemeLayer registered in profiles/default/browserlayer.xml, and to define storage for your field in profiles/default/memberdata_properties.xml.
You can see why this is necessary in plone.app.users.browser.personalpreferences. IPersonalPreferences is looked up as follows:
class PersonalPreferencesPanel(AccountPanelForm):
...
form_fields = form.FormFields(IPersonalPreferences)
...
The schema is bound to the IPersonalPreferences interface. You have to change the control panel in order to change the looked-up schema.
Instead you could use the IUserDataSchema approach described in https://pypi.python.org/pypi/collective.examples.userdata but as you've seen in order to override ##personal-information you need to use overrides.zcml which is an if-all-else-fails kind of override and not a very welcome citizen in a third party add-on.
Others may disagree but my personal preference (should I say my IPersonalPreference?) for this kind of problem is to create a dedicated form for the setting(s) and link to it from e.g. the personal tools menu.
overwriting personal-preferences should not be necessary.
just follow the documentation on https://pypi.python.org/pypi/plone.app.users
seems you're missing:
a userdatascheaprovider
from plone.app.users.userdataschema import IUserDataSchemaProvider
class UserDataSchemaProvider(object):
implements(IUserDataSchemaProvider)
def getSchema(self):
"""
"""
return IEnhancedUserDataSchema
the GS configuration for it in componentregistry.xml:
a registration of your new field in GS properties.xml to make the field show up on the registration page (optionally)
<object name="site_properties" meta_type="Plone Property Sheet">
<property name="user_registration_fields" type="lines" purge="False">
<element value="yourfield" />
</property>
</object>
to make your field show up in personal preferences follow the documentation on https://pypi.python.org/pypi/plone.app.users/1.1.5
section "How to update the personal information form"
I am trying to build a form package for a Plone website. I am currently working with Plone 4.3. Before I was using Dexterity with five.grok and grok libraries. But after reading the Plone 4.3 migration and five.grok dependency section of this article: http://developer.plone.org/components/grok.html it appears that Plone developers are moving away from using grok all together.
So should I move away from using Grok and how would I go about doing so when all the current documentation is currently using Grok? Additionally I am developing from a Windows based machine.
First creating form without grok is not that hard and do not depends on your Operating System.
Creating a form is always the same. Here is how I proceed:
Some imports
from Products.Five.browser import BrowserView
from plone.autoform.form import AutoExtensibleForm
from plone.app.z3cform import layout
from zope import interface
from zope import schema
from zope import component
from z3c.form import form
from collective.my.i18n import _
Create a schema
class AddFormSchema(interface.Interface):
what = schema.Choice(
title=_(u"What"),
vocabulary="plone.app.vocabularies.UserFriendlyTypes"
)
where = schema.Choice(
title=u"Where",
vocabulary="collective.my.vocabulary.groups"
)
create a generic adapter to fill the form from anywhere
class AddFormAdapter(object):
interface.implements(AddFormSchema)
component.adapts(interface.Interface)
def __init__(self, context):
self.what = None
self.where = None
Then write the form
class AddForm(AutoExtensibleForm, form.Form):
schema = AddFormSchema
form_name = 'add_content'
Add a view
class AddButton(layout.FormWrapper):
"""Add button"""
form = AddForm
Now ZCML time this is the step you don't need when using grok:
<adapter factory=".my.AddFormAdapter"/>
<browser:page
for="*"
name="my.addbutton"
class=".my.AddButton"
template="addbutton.pt"
permission="zope2.View"
/>
Should you move from grok:
This is depending of what are you doing. For an addon I say Yes but for a project, it's up to you.
Grok is not parts of the already big Zope. So adding dependency is something that always should be done only if needed. Grok is an option so I have never used it.
Is there a way to know if an object is Archetypes-based or Dexterity-based using only the brains resulting from a catalog search?
A Dexterity item usually has its meta_type set to 'Dexterity Item' or 'Dexterity Container'. That is available in the catalog metadata.
I don't think that this information is indexed, but it can be easily retreived by getting the FTI. The lookup can be cached when handling large result sets.
I think something like this should work:
from plone.dexterity.interfaces import IDexterityFTI
from zope.component.hooks import getSite
from Products.CMFCore.utils import getToolByName
def is_dexterity(brain):
ttool = getToolByName(getSite(), 'portal_types')
fti = ttol.get(brain.portal_type)
return IDexterityFTI.providedBy(fti)