def form_schema(self): return schema.Schema("FacebookPublicationForm", members = [ schema.Collection("subset", items = schema.Reference( type = Publishable, required = True, enumeration = lambda ctx: self.selection ), min = 1, default = schema.DynamicDefault(lambda: self.selection) ), schema.Collection("published_languages", items = schema.String( translate_value = lambda value, language = None, **kwargs: "" if not value else translations(value, language, **kwargs), enumeration = lambda ctx: self.eligible_languages ), min = 1, default = schema.DynamicDefault( lambda: self.eligible_languages ) ), schema.Collection("publication_targets", items = schema.Reference( type = FacebookPublicationTarget, required = True, enumeration = lambda ctx: self.allowed_publication_targets ), min = 1, default = schema.DynamicDefault( lambda: self.allowed_publication_targets ) ) ])
def form_model(self): from woost.extensions.staticsite import StaticSiteExtension extension = StaticSiteExtension.instance site_languages = Configuration.instance.languages def allowed_destinations(): return [ destination for destination in extension.destinations if get_current_user().has_permission( ExportationPermission, destination = destination ) ] return schema.Schema("ExportStaticSite", members = [ schema.Reference( "snapshoter", type = "woost.extensions.staticsite.staticsitesnapshoter." "StaticSiteSnapShoter", required = True, enumeration = lambda ctx: extension.snapshoters, edit_control = "cocktail.html.RadioSelector" if len(allowed_destinations()) > 1 else "cocktail.html.HiddenInput", default = schema.DynamicDefault(lambda: extension.snapshoters[0]) ), schema.Reference( "destination", type = "woost.extensions.staticsite.staticsitedestination." "StaticSiteDestination", required = True, enumeration = lambda ctx: allowed_destinations(), edit_control = "cocktail.html.RadioSelector" if len(allowed_destinations()) > 1 else "cocktail.html.HiddenInput", default = schema.DynamicDefault(lambda: allowed_destinations()[0]) ), schema.Boolean( "update_only", required = True, default = True ), schema.Boolean( "follow_links", required = True, default = True ) ])
class SignUpPage(Document): members_order = [ "user_type", "roles", "confirmation_target", "confirmation_email_template" ] # Defines the persistent class that will be # used like schema in signup process user_type = schema.Reference(class_family=User, required=True, member_group="signup_process") # The collection of roles that will be applyed # to each instance (of user_type class) created throw # a signuppage roles = schema.Collection( items="woost.models.Role", related_end=schema.Collection(name="related_signup_pages", visible=False), member_group="signup_process", relation_constraints=lambda ctx: [excluded_roles()]) # If is None, doesn't require an email confirmation # process to complete signup process confirmation_email_template = schema.Reference( type=EmailTemplate, related_end=schema.Collection(), member_group="signup_process") confirmation_target = schema.Reference(type="woost.models.Publishable", related_end=schema.Collection(), member_group="signup_process", required=True) default_template = schema.DynamicDefault(lambda: Template.get_instance( qname=u"woost.extensions.signup.signup_template")) default_controller = schema.DynamicDefault(lambda: Controller.get_instance( qname=u"woost.extensions.signup.signup_controller")) default_confirmation_email_template = schema.DynamicDefault( lambda: EmailTemplate.get_instance( qname=u"woost.extensions.signup.signup_confirmation_email_template" )) default_confirmation_target = schema.DynamicDefault( lambda: Publishable.get_instance( qname=u"woost.extensions.signup.signup_confirmation_target"))
class FacebookIdentityProvider(IdentityProvider): provider_name = "Facebook" user_identifier = "x_identity_facebook_user_id" members_order = [ "client_id", "client_secret", "scope" ] client_id = schema.String( required=True, text_search=False ) client_secret = schema.String( required=True, text_search=False ) scope = schema.Collection( min=1, default=schema.DynamicDefault(lambda: ["public_profile", "email"]), items=schema.String() ) def get_auth_url(self, target_url = None): return ( "/facebook_oauth/%d/step1?%s" % ( self.id, urlencode({ "target_url": target_url or get_request_url() }) ) )
class PayPalPaymentGateway(PaymentGateway, Implementation): instantiable = True default_label = schema.DynamicDefault( lambda: translations("PayPalPaymentGateway.label default")) members_order = [ "business", "payment_successful_page", "payment_failed_page" ] business = schema.String(required=True, shadows_attribute=True, text_search=False) payment_successful_page = schema.Reference(type=Document, related_end=schema.Reference()) payment_failed_page = schema.Reference(type=Document, related_end=schema.Reference()) def get_payment_successful_url(self, payment): if self.payment_successful_page: return self.payment_successful_page.get_uri( host="!", parameters={"payment_id": payment.id}) def get_payment_failed_url(self, payment): if self.payment_failed_page: return self.payment_failed_page.get_uri( host="!", parameters={"payment_id": payment.id})
class ChangeSet(PersistentObject): """A persistent record of a set of L{changes<Change>} performed on one or more CMS items.""" members_order = "id", "author", "date", "changes" indexed = True changes = schema.Mapping( searchable=False, get_item_key=lambda change: change.target and change.target.id) author = schema.Reference(required=True, type="woost.models.User") date = schema.DateTime(required=True, default=schema.DynamicDefault(datetime.now)) _thread_data = local() @classgetter def current(cls): return getattr(cls._thread_data, "current", None) @classgetter def current_author(cls): cs = cls.current return cs and cs.author def begin(self): if self.current: raise TypeError("Can't begin a new changeset, another changeset " "is already in place") self._thread_data.current = self def end(self): try: del self._thread_data.current except AttributeError: raise TypeError("Can't finalize the current changeset, there's no " "changeset in place") def get_searchable_text(self, languages, visited_objects=None): if visited_objects is None: visited_objects = set() elif self in visited_objects: return visited_objects.add(self) # Concatenate the descriptions of change authors and targets for language in languages: if self.author: yield translations(self.author, language) for change in self.changes.itervalues(): yield translations(change.target, language)
class Pasat4bPaymentGateway(PaymentGateway, Implementation): instantiable = True default_label = schema.DynamicDefault( lambda: translations("Pasat4bPaymentGateway.label default")) merchant_code = schema.String(required=True, shadows_attribute=True, text_search=False)
def form_schema(self): return schema.Schema( "FacebookAlbumsForm", members=[ schema.String("album_title", required=True), schema.String("album_description", edit_control="cocktail.html.TextArea"), schema.Collection( "subset", items=schema.Reference( type=File, relation_constraints=[ File.resource_type.equal("image") ], required=True, enumeration=lambda ctx: self.selection), min=1, default=schema.DynamicDefault(lambda: self.selection)), schema.Collection( "photo_languages", min=1, items=schema.String(required=True, enumeration=lambda ctx: Configuration. instance.languages, translate_value=lambda value, language= None, **kwargs: "" if not value else translations( value, language, **kwargs)), default=schema.DynamicDefault( lambda: Configuration.instance.languages)), schema.Boolean("generate_story", required=True, default=True), schema.Collection( "publication_targets", items=schema.Reference(type=FacebookPublicationTarget, required=True, enumeration=lambda ctx: self. allowed_publication_targets), min=1, default=schema.DynamicDefault( lambda: self.allowed_publication_targets)) ])
class SISPaymentGateway(PaymentGateway, Implementation): instantiable = True default_label = schema.DynamicDefault( lambda: translations("SISPaymentGateway.label default")) members_order = [ "merchant_name", "merchant_code", "merchant_terminal", "merchant_secret_key", "pay_methods", "payment_successful_page", "payment_failed_page" ] merchant_code = schema.String(required=True, shadows_attribute=True, text_search=False) merchant_name = schema.String(shadows_attribute=True, text_search=False) merchant_terminal = schema.String(required=True, shadows_attribute=True, text_search=False) merchant_secret_key = schema.String(required=True, shadows_attribute=True, text_search=False) pay_methods = schema.Collection( shadows_attribute = True, items = schema.String( enumeration = ["T", "D", "R"], translate_value = lambda value, language = None, **kwargs: \ translations("SISPaymentGateway.pay_methods=%s" % (value,)) ), edit_control = "cocktail.html.CheckList" ) payment_successful_page = schema.Reference(type=Document, related_end=schema.Reference()) payment_failed_page = schema.Reference(type=Document, related_end=schema.Reference()) def get_payment_successful_url(self, payment): if self.payment_successful_page: return self.payment_successful_page.get_uri( host="!", parameters={"paymend_id": payment.id}) def get_payment_failed_url(self, payment): if self.payment_failed_page: return self.payment_failed_page.get_uri( host="!", parameters={"paymend_id": payment.id})
def add_url_shortener_reference(e): if e.source.enabled: TwitterPublicationTarget.add_member( schema.Reference( "url_shortener", shadows_attribute=True, type=URLShortener, related_end=schema.Collection(), listed_by_default=False, # Default to the first defined service, if one exists default=schema.DynamicDefault( lambda: first(URLShortener.select()))))
class CampaignMonitorSubscriptionPage(Document): members_order = "lists", "subscription_form", "body" default_template = schema.DynamicDefault( lambda: Template.get_instance( qname = u"woost.extensions.campaignmonitor.subscription_template" ) ) default_controller = schema.DynamicDefault( lambda: Controller.get_instance( qname = u"woost.extensions.campaignmonitor.subscription_controller" ) ) body = schema.String( translated = True, listed_by_default = False, edit_control = "woost.views.RichTextEditor", member_group = "content" ) lists = schema.Collection( items = schema.Reference( type = CampaignMonitorList ), member_group = "content", listed_by_default = False ) subscription_form = schema.String( member_group = "content", default = \ "woost.extensions.campaignmonitor.subscriptionform.SubscriptionForm", text_search = False )
class UserForm(Document): groups_order = list(Document.groups_order) groups_order.insert(groups_order.index("content") + 1, "form") members_order = [ "form_model", "excluded_members", "should_save_instances", "redirection", "email_notifications" ] default_controller = schema.DynamicDefault(lambda: Controller.get_instance( qname="woost.extensions.usermodels.user_form_controller")) default_template = schema.DynamicDefault(lambda: Template.get_instance( qname="woost.extensions.usermodels.user_form_template")) form_model = schema.Reference(required=True, class_family="woost.models.Item", member_group="form") excluded_members = schema.Collection(items=schema.String(), edit_control="cocktail.html.TextArea", member_group="form") should_save_instances = schema.Boolean(required=True, default=True, member_group="form") redirection = schema.Reference(type=Publishable, related_end=schema.Collection(), member_group="form") email_notifications = schema.Collection( items=schema.Reference(type=EmailTemplate), related_end=schema.Collection(), member_group="form")
class CampaignMonitorList(Item): visible_from_root = False members_order = [ "list_id", "pending_page", "confirmation_success_page", "unsubscribe_page", ] default_pending_page = schema.DynamicDefault( lambda: StandardPage.get_instance( qname = u"woost.extensions.campaignmonitor.pending_page" ) ) title = schema.String( editable = False, listed_by_default = False, descriptive = True ) list_id = schema.String( unique = True, editable = False, text_search = False ) unsubscribe_page = schema.Reference( type = "woost.models.Publishable", related_end = schema.Collection() ) pending_page = schema.Reference( required = True, type = "woost.models.Publishable", related_end = schema.Collection() ) confirmation_success_page = schema.Reference( type = "woost.models.Publishable", related_end = schema.Collection() )
class URI(Publishable): instantiable = True type_group = "resource" groups_order = ["content"] members_order = ["title", "uri", "language_specific_uri"] default_controller = schema.DynamicDefault( lambda: Controller.get_instance(qname="woost.uri_controller")) title = schema.String(indexed=True, normalized_index=True, full_text_indexed=True, descriptive=True, translated=True, member_group="content") uri = schema.String(indexed=True, member_group="content") language_specific_uri = schema.String(translated=True, member_group="content") def get_uri(self, path=None, parameters=None, language=None, host=None, encode=True): uri = self.language_specific_uri or self.uri if uri is not None: if path: uri = make_uri(uri, *path) if parameters: uri = make_uri(uri, **parameters) uri = self._fix_uri(uri, host, encode) return uri
class TextFile(Publishable): instantiable = True per_language_publication = False default_mime_type = "text/plain" default_hidden = True default_controller = schema.DynamicDefault(lambda: Controller.get_instance( qname="woost.extensions.textfile.TextFileController")) members_order = ["title", "content"] title = schema.String(translated=True, descriptive=True, listed_by_default=False, member_group="content") content = schema.String(edit_control="cocktail.html.TextArea", listed_by_default=False, member_group="content")
class News(Document): members_order = ["news_date", "image", "summary", "blocks"] news_date = schema.Date(required=True, indexed=True, default=schema.DynamicDefault(date.today), member_group="content") image = schema.Reference(type=File, related_end=schema.Collection(), relation_constraints={"resource_type": "image"}, member_group="content") summary = schema.String(edit_control="woost.views.RichTextEditor", listed_by_default=False, translated=True, member_group="content") blocks = Slot()
class Product(Publishable): instantiable = False view_class = None members_order = [ "price", "categories", "entries" ] default_controller = schema.DynamicDefault( lambda: Controller.get_instance(qname = "woost.product_controller") ) price = schema.Decimal( required = True, default = Decimal("0") ) categories = schema.Collection( items = "woost.extensions.shop.productcategory.ProductCategory", bidirectional = True ) entries = schema.Collection( items = "woost.extensions.shop.shoporderentry.ShopOrderEntry", bidirectional = True, visible = False, block_delete = True ) def discounts(self): """Returns the discounts that can be applied to the product. @rtype: L{Product<woost.extensions.shop.product.Product>} """ from woost.extensions.shop import ShopExtension return [discount for discount in ShopExtension.instance.discounts if discount.applies_to(self)]
class SlideShowBlock(Block): instantiable = True view_class = "woost.views.SlideShowBlockView" groups_order = [ "content", "transition_settings", "controls", "behavior", "html", "administration" ] members_order = [ "element_type", "slides", "autoplay", "interval", "transition_effect", "transition_duration", "navigation_controls", "bullet_controls", "bullet_view_class", "bullet_image_factory" ] element_type = ElementType(enumeration=list(ElementType.enumeration), member_group="content") for et in ("nav", "dd"): try: element_type.enumeration.remove(et) except: pass slides = Slot() autoplay = schema.Boolean(required=True, default=True, member_group="transition_settings") interval = schema.Integer(required=autoplay, default=3000, min=0, member_group="transition_settings") transition_effect = schema.String(required=True, default="fade", enumeration=["fade", "topBottomSlide"], member_group="transition_settings") transition_duration = schema.Integer(required=True, default=500, min=0, member_group="transition_settings") navigation_controls = schema.Boolean(required=True, default=False, member_group="controls") bullet_controls = schema.Boolean(required=True, default=False, member_group="controls") bullet_view_class = schema.String( required=True, default="woost.views.SlideShowButtonBullet", enumeration=[ "woost.views.SlideShowButtonBullet", "woost.views.SlideShowTextBullet", "woost.views.SlideShowImageBullet", "woost.views.SlideShowTextAndImageBullet" ], member_group="controls") bullet_image_factory = schema.Reference( type=ImageFactory, related_end=schema.Collection(), required=True, default=schema.DynamicDefault(lambda: ImageFactory.get_instance( identifier="image_gallery_thumbnail")), member_group="controls") def init_view(self, view): Block.init_view(self, view) view.tag = self.element_type view.autoplay = self.autoplay view.interval = self.interval view.transition_effect = self.transition_effect view.transition_duration = self.transition_duration view.navigation_controls = self.navigation_controls view.bullet_controls = self.bullet_controls view.bullet_view_class = self.bullet_view_class view.bullet_image_factory = self.bullet_image_factory for block_view in create_block_views(self.slides): view.slides.append(block_view)
from cocktail import schema from cocktail.html.datadisplay import display_factory from cocktail.iteration import first from .configuration import Configuration from .rendering import ImageFactory def _iter_block_image_factories(): for factory in Configuration.instance.image_factories: if factory.applicable_to_blocks: yield factory def _block_image_factories_enumeration(ctx): return list(_iter_block_image_factories()) _block_image_factories_default = schema.DynamicDefault( lambda: first(_iter_block_image_factories()) ) _mandatory_dropdown = display_factory( "cocktail.html.DropdownSelector", empty_option_displayed = False ) class BlockImageFactoryReference(schema.Reference): def __init__(self, *args, **kwargs): kwargs.setdefault("required", True) kwargs.setdefault("type", ImageFactory) kwargs.setdefault("enumeration", _block_image_factories_enumeration)
class ECommerceOrder(Item): payment_types_completed_status = { "payment_gateway": "accepted", "transfer": "payment_pending", "cash_on_delivery": "payment_pending" } incoming = Event(doc=""" An event triggered when a new order is received. """) completed = Event(doc=""" An event triggered when an order is completed. """) groups_order = ["shipping_info", "billing"] members_order = [ "customer", "address", "town", "region", "country", "postal_code", "language", "status", "purchases", "payment_type", "total_price", "pricing", "total_shipping_costs", "shipping_costs", "total_taxes", "taxes", "total" ] customer = schema.Reference( type=User, related_end=schema.Collection(), required=True, default=schema.DynamicDefault(get_current_user)) address = schema.String(member_group="shipping_info", required=True, listed_by_default=False) town = schema.String(member_group="shipping_info", required=True, listed_by_default=False) region = schema.String(member_group="shipping_info", required=True, listed_by_default=False) country = schema.Reference( member_group="shipping_info", type=Location, relation_constraints=[Location.location_type.equal("country")], default_order="location_name", related_end=schema.Collection(), required=True, listed_by_default=False, user_filter="cocktail.controllers.userfilter.MultipleChoiceFilter") postal_code = schema.String(member_group="shipping_info", required=True, listed_by_default=False) language = schema.String( required=True, format="^[a-z]{2}$", editable=False, default=schema.DynamicDefault(get_language), text_search=False, translate_value=lambda value, language=None, **kwargs: u"" if not value else translations(value, language, **kwargs)) status = schema.String( required=True, indexed=True, enumeration=[ "shopping", "payment_pending", "accepted", "failed", "refund" ], default="shopping", text_search=False, translate_value=lambda value, language=None, **kwargs: u"" if not value else translations("ECommerceOrder.status-" + value, language, **kwargs)) purchases = schema.Collection( items="woost.extensions.ecommerce.ecommercepurchase." "ECommercePurchase", integral=True, bidirectional=True, min=1) payment_type = schema.String( member_group="billing", required=True, translate_value=lambda value, language=None, **kwargs: translations( "ECommerceOrder.payment_type-%s" % value, language=language), default=schema.DynamicDefault(_get_default_payment_type), text_search=False, edit_control="cocktail.html.RadioSelector", listed_by_default=False) total_price = schema.Decimal(member_group="billing", editable=False, listed_by_default=False, translate_value=_translate_amount) pricing = schema.Collection( member_group="billing", items=schema.Reference(type=ECommerceBillingConcept), related_end=schema.Collection(block_delete=True), editable=False) total_shipping_costs = schema.Decimal(member_group="billing", editable=False, listed_by_default=False, translate_value=_translate_amount) shipping_costs = schema.Collection( member_group="billing", items=schema.Reference(type=ECommerceBillingConcept), related_end=schema.Collection(block_delete=True), editable=False) total_taxes = schema.Decimal(member_group="billing", editable=False, listed_by_default=False, translate_value=_translate_amount) taxes = schema.Collection( member_group="billing", items=schema.Reference(type=ECommerceBillingConcept), related_end=schema.Collection(block_delete=True), editable=False) total = schema.Decimal(member_group="billing", editable=False, translate_value=_translate_amount) def calculate_cost(self, apply_pricing=True, apply_shipping_costs=True, apply_taxes=True): """Calculates the costs for the order. :rtype: dict """ from woost.extensions.ecommerce import ECommerceExtension extension = ECommerceExtension.instance order_costs = { "price": { "cost": Decimal("0.00"), "percentage": Decimal("0.00"), "concepts": [] }, "shipping_costs": { "cost": Decimal("0.00"), "percentage": Decimal("0.00"), "concepts": [] }, "taxes": { "cost": Decimal("0.00"), "percentage": Decimal("0.00"), "concepts": [] }, "purchases": {} } # Per purchase costs: for purchase in self.purchases: purchase_costs = purchase.calculate_costs( apply_pricing=apply_pricing, apply_shipping_costs=apply_shipping_costs, apply_taxes=apply_taxes) order_costs["purchases"][purchase] = purchase_costs order_costs["price"]["cost"] += purchase_costs["price"]["total"] order_costs["shipping_costs"]["cost"] += \ purchase_costs["shipping_costs"]["total"] order_costs["taxes"]["cost"] += purchase_costs["taxes"]["total"] # Order price order_price = order_costs["price"] if apply_pricing: for pricing in extension.pricing: if pricing.applies_to(self): pricing.apply(self, order_price) order_price["cost"] += \ order_price["cost"] * order_price["percentage"] / 100 order_price["total"] = order_price["cost"] # Order shipping costs order_shipping_costs = order_costs["shipping_costs"] if apply_shipping_costs: for shipping_cost in extension.shipping_costs: if shipping_cost.applies_to(self): shipping_cost.apply(self, order_shipping_costs) order_shipping_costs["total"] = ( order_shipping_costs["cost"] + order_price["total"] * order_shipping_costs["percentage"] / 100) # Order taxes order_taxes = order_costs["taxes"] if apply_taxes: for tax in extension.taxes: if tax.applies_to(self): tax.apply(self, order_taxes) order_taxes["total"] = ( order_taxes["cost"] + order_price["total"] * order_taxes["percentage"] / 100) # Total order_costs["total"] = (order_price["total"] + order_shipping_costs["total"] + order_taxes["total"]) return order_costs def update_cost(self, apply_pricing=True, apply_shipping_costs=True, apply_taxes=True): costs = self.calculate_cost(apply_pricing=apply_pricing, apply_shipping_costs=apply_shipping_costs, apply_taxes=apply_taxes) self.total_price = costs["price"]["total"] self.pricing = list(costs["price"]["concepts"]) self.total_shipping_costs = costs["shipping_costs"]["total"] self.shipping_costs = list(costs["shipping_costs"]["concepts"]) self.total_taxes = costs["taxes"]["total"] self.taxes = list(costs["taxes"]["concepts"]) self.total = costs["total"] for purchase, purchase_costs in costs["purchases"].iteritems(): purchase.total_price = purchase_costs["price"]["total"] purchase.pricing = list(purchase_costs["price"]["concepts"]) self.pricing.extend(purchase.pricing) purchase.total_shipping_costs = \ purchase_costs["shipping_costs"]["total"] purchase.shipping_costs = \ list(purchase_costs["shipping_costs"]["concepts"]) self.shipping_costs.extend(purchase.shipping_costs) purchase.total_taxes = purchase_costs["taxes"]["total"] purchase.taxes = list(purchase_costs["taxes"]["concepts"]) self.taxes.extend(purchase.taxes) purchase.total = purchase_costs["total"] def count_units(self): return sum(purchase.quantity for purchase in self.purchases) def get_weight(self): return sum(purchase.get_weight() for purchase in self.purchases) def add_purchase(self, purchase): for order_purchase in self.purchases: if order_purchase.__class__ is purchase.__class__ \ and order_purchase.product is purchase.product \ and all( order_purchase.get(option) == purchase.get(option) for option in purchase.get_options() if option.name != "quantity" ): order_purchase.quantity += purchase.quantity purchase.product = None if purchase.is_inserted: purchase.delete() break else: self.purchases.append(purchase) @classmethod def get_public_schema(cls): public_schema = schema.Schema("OrderCheckoutSummary") cls.get_public_adapter().export_schema(cls, public_schema) payment_type = public_schema.get_member("payment_type") if payment_type: payments = PaymentsExtension.instance if payments.enabled and payments.payment_gateway: translate_value = payment_type.translate_value def payment_type_translate_value(value, language=None, **kwargs): if value == "payment_gateway": return payments.payment_gateway.label else: return translate_value(value, language=language, **kwargs) payment_type.translate_value = payment_type_translate_value return public_schema @classmethod def get_public_adapter(cls): from woost.extensions.ecommerce import ECommerceExtension user = get_current_user() adapter = schema.Adapter() adapter.exclude(["customer", "status", "purchases"]) adapter.exclude([ member.name for member in cls.members().itervalues() if not member.visible or not member.editable or not issubclass(member.schema, ECommerceOrder) or not user.has_permission(ModifyMemberPermission, member=member) ]) if len(ECommerceExtension.instance.payment_types) == 1: adapter.exclude(["payment_type"]) return adapter @property def is_completed(self): return self.status \ and self.status == self.payment_types_completed_status.get( self.payment_type ) @event_handler def handle_changed(cls, event): item = event.source member = event.member if member.name == "status": if event.previous_value == "shopping" \ and event.value in ("payment_pending", "accepted"): item.incoming() if item.is_completed: item.completed() def get_description_for_gateway(self): site_name = Configuration.instance.get_setting("site_name") if site_name: return translations( "woost.extensions.ECommerceOrder description for gateway" ) % site_name else: return translations(self)
member = OpenGraphType.category Publishable.add_member( schema.Boolean("x_opengraph_enabled", required=True, default=True, listed_by_default=False, member_group="meta.x_opengraph")) Publishable.add_member( schema.Reference("x_opengraph_type", type=OpenGraphType, required=Publishable["x_opengraph_enabled"], related_end=schema.Collection(block_delete=True), default=schema.DynamicDefault( lambda: OpenGraphType.get_instance(code="article")), indexed=True, listed_by_default=False, member_group="meta.x_opengraph")) def _get_publishable_properties(self): properties = { "og:title": translations(self), "og:type": self.x_opengraph_type.code, "og:url": self.get_uri(host="!") } description = self.x_opengraph_get_description() if description:
class TextBlock(Block): instantiable = True view_class = "woost.views.TextBlockView" block_display = "woost.views.TextBlockDisplay" edit_form = "woost.views.TextBlockForm" groups_order = [ "content", "images", "link", "behavior", "html", "administration" ] members_order = [ "element_type", "text", "images", "image_alignment", "image_thumbnail_factory", "image_close_up_enabled", "image_close_up_factory", "image_close_up_preload", "image_labels_visible", "image_original_link_visible", "link_destination", "link_parameters", "link_opens_in_new_window" ] element_type = ElementType( member_group = "content" ) text = schema.String( edit_control = "woost.views.RichTextEditor", translated = True, member_group = "content" ) images = schema.Collection( items = schema.Reference(type = File), related_end = schema.Collection(), relation_constraints = [File.resource_type.equal("image")], member_group = "images", invalidates_cache = True ) image_alignment = schema.String( required = True, default = "float_top_left", enumeration = [ "float_top_left", "float_top_right", "column_left", "column_right", "top_left", "top_right", "bottom_left", "center_top", "center_bottom", "inline", "background", "fallback" ], edit_control = _mandatory_dropdown, member_group = "images" ) image_thumbnail_factory = BlockImageFactoryReference( required = True, member_group = "images" ) image_close_up_enabled = schema.Boolean( required = True, default = False, member_group = "images" ) image_close_up_factory = BlockImageFactoryReference( required = True, default = schema.DynamicDefault( lambda: ImageFactory.get_instance(identifier = "gallery_close_up") ), member_group = "images" ) image_close_up_preload = schema.Boolean( required = True, default = True, member_group = "images" ) image_labels_visible = schema.Boolean( required = True, default = False, member_group = "images" ) image_original_link_visible = schema.Boolean( required = True, default = False, member_group = "images" ) def get_block_image(self): for image in self.images: return image else: return Block.get_block_image(self) link_destination = schema.Reference( type = Publishable, related_end = schema.Collection(), member_group = "link", invalidates_cache = True ) link_parameters = schema.String( edit_control = "cocktail.html.TextArea", member_group = "link" ) link_opens_in_new_window = schema.Boolean( default = False, required = True, member_group = "link" ) def init_view(self, view): Block.init_view(self, view) if self.element_type == "dd": view.tag = None view.content_wrapper.tag = "dd" else: view.tag = self.element_type def get_block_proxy(self, view): if self.element_type == "dd": return view.content_wrapper return view
class File(Publishable): instantiable = True cacheable = False type_group = "resource" edit_node_class = \ "woost.controllers.backoffice.fileeditnode.FileEditNode" backoffice_heading_view = "woost.views.BackOfficeFileHeading" video_player = "cocktail.html.MediaElementVideo" default_mime_type = None default_encoding = None default_controller = schema.DynamicDefault( lambda: Controller.get_instance(qname="woost.file_controller")) members_order = ["title", "file_name", "file_size", "file_hash"] title = schema.String(indexed=True, normalized_index=True, full_text_indexed=True, descriptive=True, translated=True, member_group="content") file_name = schema.String(required=True, editable=False, member_group="content") file_size = schema.Integer( required=True, editable=False, translate_value=lambda size, language=None, **kwargs: "" if size in (None, "") else format_bytes(size), min=0, member_group="content") file_hash = schema.String(visible=False, searchable=False, text_search=False, member_group="content") @property def file_extension(self): return os.path.splitext(self.file_name)[1] @property def file_path(self): return app.path("upload", str(self.id)) @classmethod def from_path(cls, path, dest=None, languages=None, hash=None, encoding="utf-8", download_temp_folder=None, redownload=False): """Imports a file into the site. @param path: The path to the file that should be imported. @type path: str @param dest: The base path where the file should be copied (should match the upload folder for the application). @type dest: str @param languages: The set of languages that the created file will be translated into. @type languages: str set @return: The created file. @rtype: L{File} """ # The default behavior is to translate created files into all the languages # defined by the site if languages is None: from woost.models import Configuration languages = Configuration.instance.languages file_name = os.path.split(path)[1] title, ext = os.path.splitext(file_name) # Download remote files if "://" in path: if not download_temp_folder: download_temp_folder = mkdtemp() temp_path = os.path.join(download_temp_folder, file_name) if redownload or not os.path.exists(temp_path): response = urlopen(path) with open(temp_path, "w") as temp_file: copyfileobj(response, temp_file) path = temp_path if encoding: if isinstance(title, str): title = title.decode(encoding) if isinstance(file_name, str): file_name = file_name.decode(encoding) title = title.replace("_", " ").replace("-", " ") title = title[0].upper() + title[1:] file = cls() file.file_size = os.stat(path).st_size file.file_hash = hash or file_hash(path) file.file_name = file_name # Infer the file's MIME type mime_type = guess_type(file_name, strict=False) if mime_type: file.mime_type = mime_type[0] for language in languages: file.set("title", title, language) if dest is None: upload_path = file.file_path else: upload_path = os.path.join(dest, str(file.id)) copy(path, upload_path) return file
class GoogleIdentityProvider(IdentityProvider): provider_name = "Google" user_identifier = "x_identity_google_user_id" members_order = ["client_id", "client_secret", "scope", "access_type"] client_id = schema.String(required=True, text_search=False) client_secret = schema.String(required=True, text_search=False) scope = schema.Collection( min=1, default=schema.DynamicDefault(lambda: ["profile", "email"]), items=schema.String()) access_type = schema.String(required=True, default="online", enumeration=["online", "offline"], edit_control="cocktail.html.RadioSelector") def get_auth_url(self, target_url=None): return ("/google_oauth/%d/step1?%s" % (self.id, urllib.parse.urlencode( {"target_url": target_url or str(get_request_url())}))) def get_refresh_token_url(self, redirect_uri=None): """ Produces the URL to initiate a browser driven request to get a refresh code. """ OAUTH_URL = "https://accounts.google.com/o/oauth2/auth" if not redirect_uri: website = (app.website or Configuration.instance.websites[0]) redirect_uri = "http://%s/google_oauth/%d/refresh_token" % ( website.hosts[0], self.id) params = { "client_id": self.client_id, "redirect_uri": redirect_uri, "scope": " ".join(self.scope), "response_type": "code", "access_type": self.access_type, "approval_prompt": "force" } return "{}?{}".format(OAUTH_URL, urllib.parse.urlencode(params)) def get_refresh_token_from_browser(self, redirect_uri=None): """ Opens the browser to get user authorization and shows the authorization code. """ import webbrowser url = self.get_refresh_token_url(redirect_uri) webbrowser.open(url) def get_refresh_token(self, code, redirect_uri=None): """ Gets an authorization token with access_token and refresh_token from an authorization code. :param code: A valid authorization code with access_type offline :return: A dict representing the authorization token. The 'access_token' key is a valid access token and the 'refresh_token' key can be used to generate new valid access tokens """ TOKEN_URL = "https://accounts.google.com/o/oauth2/token" if not redirect_uri: website = (app.website or Configuration.instance.websites[0]) redirect_uri = "http://%s/google_oauth/%d/refresh_token" % ( website.hosts[0], self.id) params = { "code": code, "client_id": self.client_id, "client_secret": self.client_secret, "redirect_uri": redirect_uri, "grant_type": "authorization_code" } request = urllib.request.Request(url=TOKEN_URL, data=urllib.parse.urlencode(params)) json_file = urllib.request.urlopen(request).read() auth_token = json.loads(json_file) if self.debug_mode: print(styled("Google refresh token:", "magenta"), auth_token) return auth_token def get_access_token_from_refresh_token(self, refresh_token): """ Gets a new access token from a refresh token. :return: A dict respresenting an access token. Its 'access_token' key is a valid access token """ TOKEN_URL = "https://accounts.google.com/o/oauth2/token" params = { "client_id": self.client_id, "client_secret": self.client_secret, "refresh_token": refresh_token, "grant_type": "refresh_token" } request = urllib.request.Request(url=TOKEN_URL, data=urllib.parse.urlencode(params)) try: json_file = urllib.request.urlopen(request).read() except urllib.error.HTTPError as e: if self.debug_mode: print( styled( "Error while obtaining a Google access token from a " "refresh token:", "magenta")) print(e.read()) raise access_token = json.loads(json_file) if self.debug_mode: print(styled("Google access token from refresh token:", "magenta"), end=' ') print(access_token) return access_token
class User(Item): """An application user. @ivar anonymous: Indicates if this is the user that represents anonymous users. To handle anonymous access to the application, an instance of the User class is designated to represent anonymous users. This allows uniform treatment of both anonymous and authenticated access (ie. authorization checks). This property indicates if the user it is invoked on is the instance used to represent anonymous users. @type anonymous: bool @ivar encryption_method: The hashing algorithm used to encrypt user passwords. Should be a reference to one of the algorithms provided by the L{hashlib} module. """ type_group = "users" edit_form = "woost.views.UserForm" edit_node_class = \ "woost.controllers.backoffice.usereditnode.UserEditNode" encryption_method = sha1 anonymous = False members_order = ["enabled", "email", "password", "prefered_language"] email = schema.String(required=True, unique=True, descriptive=True, max=255, indexed=True, format="^.+@.+$") password = schema.String(required=True, listable=False, listed_by_default=False, searchable=False, text_search=False, synchronizable=False, min=8, visible_in_detail_view=False, edit_control="cocktail.html.PasswordBox") def _backoffice_language_default(): from woost.models.configuration import Configuration return Configuration.instance.backoffice_language def _backoffice_language_enumeration(ctx): from woost.models.configuration import Configuration return Configuration.backoffice_language.enumeration prefered_language = schema.String( required=True, default=schema.DynamicDefault(_backoffice_language_default), enumeration=_backoffice_language_enumeration, translate_value=lambda value, language=None, **kwargs: "" if value is None else translations(value, language, **kwargs), text_search=False) del _backoffice_language_default del _backoffice_language_enumeration roles = schema.Collection(items="woost.models.Role", bidirectional=True) enabled = schema.Boolean(required=True, default=True) @classmethod def encryption(cls, data): if cls.encryption_method: if isinstance(data, unicode): data = data.encode("utf-8") data = cls.encryption_method(data).hexdigest() return data @event_handler def handle_changing(cls, event): if event.member is cls.password \ and event.value is not None: event.value = cls.encryption(event.value) def test_password(self, password): """Indicates if the user's password matches the given string. @param password: An unencrypted string to tests against the user's encrypted password. @type password: str @return: True if the passwords match, False otherwise. @rtype: bool """ if password: return self.encryption(password) == self.password else: return not self.password def iter_roles(self, recursive=True): """Obtains all the roles that apply to the user. The following roles can be yielded: * The user's L{explicit roles<roles>} will be yielded if defined * An 'authenticated' role will be yielded if the user is not L{anonymous} * An 'everybody' role that applies to all users will always be yielded Roles are sorted in descending relevancy order. @return: An iterable sequence of roles that apply to the user. @rtype: L{Role} """ explicit_roles = self.roles if explicit_roles: if recursive: for role in explicit_roles: for ancestor_role in role.iter_roles(): yield ancestor_role else: for role in explicit_roles: yield role for role in self.iter_implicit_roles(): yield role def iter_implicit_roles(self): if not self.anonymous: yield Role.require_instance(qname="woost.authenticated") yield Role.require_instance(qname="woost.everybody") def has_role(self, role): """Determines if the user has been granted the indicated role. This takes into account inherited and implicit roles. @return: True if the user possesses the given role, False otherwise. @rtype: bool """ for user_role in self.iter_roles(): if user_role is role: return True return False def iter_permissions(self, permission_type=None): """Iterates over the permissions granted to the user's roles. This method yields all permissions that are granted to any of the user's roles. @param permission_type: If given, restricts the list of returned permissions to those of the given type (or a subclass of that type). By default, all permissions are yielded, regardless of their type. @type permission_type: L{Permission} subclass @return: An iterable sequence of permissions granted to any of the user's roles. @rtype: L{Permission} sequence """ for role in self.iter_roles(False): for permission in role.iter_permissions(permission_type): yield permission def has_permission(self, permission_type, verbose=None, **context): """Determines if the user is given permission to perform an action. @param permission_type: The kind of permission to assert. @type permission_type: L{Permission} subclass @param verbose: A boolean flag that enables or disables on screen reporting of the checks executed by this method. Can help debugging authorization issues. When set, overrides the value of the module L{verbose} flag. @type verbose: bool @param context: Keyword parameters to supply to each tested permission. Each parameter will be forwarded to the permission's L{match<woost.models.permission.Permission.match>} method. Each subclass or L{Permission<woost.models.permission.Permission>} can define its set of required parameters, and all of its subclasses must implement exactly that set. @return: True if the user is granted permission, else False. @rtype: bool """ if verbose is None: verbose = globals()["verbose"] if verbose: role = None print permission_check_style(translations(permission_type.name)) print permission_param_style("user", translations(self)) for key, value in context.iteritems(): if isinstance(value, type): value = translations(value.name) else: trans = translations(value) if trans and isinstance(value, Item): value = u"%s (%s)" % (unicode(value), trans) else: value = trans or unicode(value) print permission_param_style(key, value) permissions = self.iter_permissions(permission_type) for permission in permissions: if verbose: new_role = permission.role if new_role is not role: role = new_role print role_style(translations(role)) print permission_style( "#%d. %s" % (permission.id, translations(permission))) if permission.match(verbose=verbose, **context): if permission.authorized: if verbose: print authorized_style("authorized") return True else: break return permission_type.permission_not_found(self, verbose=verbose, **context) def require_permission(self, permission_type, verbose=None, **context): """Asserts the user has permission to perform an action. This method is similar to L{has_permission}, but instead of returning a boolean value, it will raise an exception if the permission is not granted. @param permission_type: The kind of permission to assert. @type permission_type: L{Permission} subclass @param verbose: A boolean flag that enables or disables on screen reporting of the checks executed by this method. Can help debugging authorization issues. When set, overrides the value of the module L{verbose} flag. @type verbose: bool @param context: Keyword parameters to supply to each tested permission. Each parameter will be forwarded to the permission's L{match<woost.models.permission.Permission.match>} method. Each subclass or L{Permission<woost.models.permission.Permission>} can define its set of required parameters, and all of its subclasses must implement exactly that set. @raise L{AuthorizationError}: Raised if the user doesn't have the specified permission. """ if not self.has_permission(permission_type, verbose=verbose, ** context): raise AuthorizationError(user=self, permission_type=permission_type, context=context)
class Feed(Publishable): type_group = "setup" instantiable = True groups_order = ["meta", "feed_items"] members_order = [ "title", "ttl", "image", "description", "limit", "query_parameters", "item_title_expression", "item_link_expression", "item_publication_date_expression", "item_description_expression" ] default_mime_type = u"application/rss+xml" default_controller = schema.DynamicDefault( lambda: Controller.get_instance(qname="woost.feed_controller")) edit_controller = \ "woost.controllers.backoffice.feedfieldscontroller." \ "FeedFieldsController" edit_view = "woost.views.FeedFields" title = schema.String(indexed=True, normalized_index=True, full_text_indexed=True, descriptive=True, translated=True, member_group="meta") ttl = schema.Integer(listed_by_default=False, member_group="meta") image = schema.Reference( type=Publishable, related_end=schema.Collection(), relation_constraints=Publishable.resource_type.equal("image"), member_group="meta") description = schema.String(required=True, translated=True, listed_by_default=False, edit_control="cocktail.html.TextArea", member_group="meta") limit = schema.Integer(min=1, listed_by_default=False, member_group="feed_items") query_parameters = schema.Mapping(keys=schema.String(), required=True, listed_by_default=False, member_group="feed_items") item_title_expression = schema.CodeBlock(language="python", required=True, default="translations(item)", member_group="feed_items") item_link_expression = schema.CodeBlock(language="python", required=True, default="cms.uri(item)", member_group="feed_items") item_publication_date_expression = schema.CodeBlock( language="python", required=True, default="item.start_date or item.creation_time", member_group="feed_items") item_description_expression = schema.CodeBlock(language="python", required=True, default="item.description", member_group="feed_items") def select_items(self): user_collection = UserCollection(Publishable) user_collection.allow_paging = False user_collection.allow_member_selection = False user_collection.allow_language_selection = False user_collection.params.source = self.query_parameters.get user_collection.available_languages = \ Configuration.instance.get_enabled_languages() items = user_collection.subset if self.limit: items.range = (0, self.limit) return items
class ShopOrder(Item): members_order = [ "address", "town", "region", "country", "postal_code", "cost", "entries" ] address = schema.String(member_group="shipping_info", required=True, listed_by_default=False) town = schema.String(member_group="shipping_info", required=True, listed_by_default=False) region = schema.String(member_group="shipping_info", required=True, listed_by_default=False) country = schema.Reference( member_group="shipping_info", type=Country, related_end=schema.Collection(), required=True, listed_by_default=False, user_filter="cocktail.controllers.userfilter.MultipleChoiceFilter") postal_code = schema.String(member_group="shipping_info", required=True, listed_by_default=False) cost = schema.Decimal(required=True, default=Decimal("0"), editable=False) language = schema.String( required=True, format="^[a-z]{2}$", editable=False, default=schema.DynamicDefault(get_language), text_search=False, translate_value=lambda value, language=None, **kwargs: u"" if not value else translations(value, language, **kwargs)) status = schema.String( required=True, indexed=True, enumeration=["pending", "accepted", "failed"], default="pending", text_search=False, translate_value=lambda value, language=None, **kwargs: u"" if not value else translations( "woost.extensions.shop.ShopOrder.status " + value, language, ** kwargs)) entries = schema.Collection( items="woost.extensions.shop.shoporderentry.ShopOrderEntry", integral=True, bidirectional=True, min=1) def calculate_cost(self, include_shipping=True, include_taxes=True, include_discounts=True): """Calculates the costs for the order. @rtype: dict """ costs = { "pricing_policies": [], "price": { "cost": 0, "percentage": 0, "total": None }, "shipping": 0, "tax": { "cost": 0, "percentage": 0 }, "entries": [{ "pricing_policies": [], "quantity": entry.quantity, "paid_quantity": entry.quantity, "price": { "cost": entry.product.price, "percentage": 0 }, "shipping": 0, "tax": { "cost": 0, "percentage": 0 } } for entry in self.entries] } from woost.extensions.shop import ShopExtension shop_ext = ShopExtension.instance policies = list() if include_discounts: policies.extend(shop_ext.discounts) if include_shipping: policies.extend(shop_ext.shipping_costs) if include_taxes: policies.extend(shop_ext.taxes) for pricing_policy in policies: matching_items = pricing_policy.select_matching_items() if issubclass(matching_items.type, ShopOrder): if pricing_policy.applies_to(self): pricing_policy.apply(self, costs) costs["pricing_policies"].append(pricing_policy) else: for entry, entry_costs in zip(self.entries, costs["entries"]): if pricing_policy.applies_to(entry.product): pricing_policy.apply(entry.product, entry_costs) entry_costs["pricing_policies"].append(pricing_policy) # Total price def apply_percentage(costs): cost = costs["cost"] percentage = costs["percentage"] if percentage: cost += cost * percentage / 100 costs["total"] = cost return cost total_price = apply_percentage(costs["price"]) for entry_costs in costs["entries"]: entry_price = apply_percentage(entry_costs["price"]) entry_total_price = entry_price * entry_costs["paid_quantity"] entry_costs["total_price"] = entry_total_price total_price += entry_total_price costs["total_price"] = total_price # Total taxes total_taxes = costs["tax"]["cost"] \ + total_price * costs["tax"]["percentage"] / 100 for entry_costs in costs["entries"]: quantity = entry_costs["paid_quantity"] entry_price = entry_costs["price"]["total"] * quantity entry_taxes = entry_costs["tax"]["cost"] * quantity \ + entry_price * entry_costs["tax"]["percentage"] / 100 total_taxes += entry_taxes entry_costs["tax"]["total"] = entry_taxes costs["total_taxes"] = total_taxes # Total shipping costs total_shipping_costs = costs["shipping"] \ + sum(entry_costs["shipping"] * entry_costs["quantity"] for entry_costs in costs["entries"]) costs["total_shipping_costs"] = total_shipping_costs # Grand total costs["total"] = total_price + total_taxes + total_shipping_costs return costs def count_items(self): """Gets the number of purchased product units in the order. @rtype: int """ return sum(entry.quantity for entry in self.entries) def get_product_entry(self, product): """Gets the entry in the order for the given product. @param product: The product to obtain the entry for. @type product: L{Product<woost.extensions.shop.product.Product>} @return: The matching entry, or None if the order doesn't contain an entry for the indicated product. @rtype: L{ShopOrderEntry <woost.extensions.shop.shoporderentry.ShopOrderEntry>} """ for entry in self.entries: if entry.product is product: return entry def set_product_quantity(self, product, quantity): """Updates the quantity of ordered units for the indicated product. If an entry for the given product already exists, its quantity will be updated to the indicated value. If the indicated quantity is zero, the entry will be removed from the order. If no matching entry exists, a new entry for the product will be created with the specified amount of units. @param product: The product to set the quantity for. @type product: L{Product<woost.extensions.shop.product.Product>} @param quantity: The number of units of the product to order. @type quantity: int """ entry = self.get_product_entry(product) if entry is None: if quantity: entry = ShopOrderEntry(product=product, quantity=quantity) self.entries.append(entry) if self.is_inserted: entry.insert() else: if quantity: entry.quantity = quantity else: if entry.is_inserted: entry.delete() else: self.entries.remove(entry)
class ECommerceProduct(Publishable): instantiable = False members_order = [ "description", "price", "weight", "attachments", "purchase_model", "purchases", "template" ] default_controller = schema.DynamicDefault( lambda: Controller.get_instance( qname = "woost.extensions.ecommerce.product_controller" ) ) description = schema.String( translated = True, edit_control = "woost.views.RichTextEditor", member_group = "product_data" ) price = schema.Decimal( required = True, default = Decimal("0"), member_group = "product_data" ) weight = schema.Decimal( translate_value = lambda value, language = None, **kwargs: "" if not value else "%s Kg" % translations(value, language), member_group = "product_data" ) attachments = schema.Collection( items = schema.Reference(type = File), related_end = schema.Collection(), member_group = "product_data" ) purchase_model = schema.Reference( class_family = "woost.extensions.ecommerce.ecommercepurchase." "ECommercePurchase", default = schema.DynamicDefault( lambda: ECommerceProduct.purchase_model.class_family ), required = True, searchable = False, member_group = "product_data" ) purchases = schema.Collection( items = "woost.extensions.ecommerce.ecommercepurchase." "ECommercePurchase", bidirectional = True, visible = False, member_group = "product_data" ) template = schema.Reference( type = Template, related_end = schema.Collection(), default = schema.DynamicDefault( lambda: Template.get_instance( qname = "woost.extensions.ecommerce.product_template" ) ), member_group = "presentation" ) def get_image(self): for attachment in self.attachments: if attachment.resource_type == "image" \ and attachment.is_accessible(): return attachment def offers(self): from woost.extensions.ecommerce import ECommerceExtension for pricing in ECommerceExtension.instance.pricing: if not pricing.hidden and pricing.applies_to(self): yield pricing @getter def inherited_resources(self): if self.inherit_resources and self.parent is None: catalog = Document.get_instance( qname = "woost.extensions.ecommerce.catalog_page" ) if catalog: for resource in catalog.inherited_resources: yield resource for resource in catalog.branch_resources: yield resource else: for resource in Publishable.inherited_resources.__get__(self): yield resource
class IssuuDocument(Publishable): instantiable = True default_per_language_publication = True type_group = "resource" default_controller = schema.DynamicDefault(lambda: Controller.get_instance( qname="woost.issuu_document_controller")) members_order = ["title", "issuu_document_url", "thumbnail_page"] title = schema.String(indexed=True, normalized_index=True, full_text_indexed=True, descriptive=True, translated=True, required=True, member_group="content") issuu_document_url = schema.URL(required=True, format=ISSUU_DOCUMENT_URL_PATTERN, searchable=False, member_group="content") thumbnail_page = schema.Integer(required=True, default=1, min=1, member_group="content", listed_by_default=False) issuu_document_id = schema.String(editable=False, unique=True, indexed=True, searchable=False, member_group="content", listed_by_default=False) issuu_config_id = schema.String(editable=False, searchable=False, member_group="content", listed_by_default=False) def get_issuu_uri(self, page_number=None): if page_number == None: page_number = self.thumbnail_page return u"http://issuu.com/%s/docs/%s/%s?e=%s" % ( self.issuu_document_username, self.issuu_document_name, page_number, self.issuu_config_id) def get_uri(self, path=None, parameters=None, language=None, host=None, encode=True): uri = self.get_issuu_uri() if uri is not None: if path: uri = make_uri(uri, *path) if parameters: uri = make_uri(uri, **parameters) uri = self._fix_uri(uri, host, encode) return uri @event_handler def handle_changed(cls, event): item = event.source member = event.member if member.name == "issuu_document_url": item._update_issuu_document_metadata() def _update_issuu_document_metadata(self, timeout=5): if self.issuu_document_url: metadata = extract_issuu_document_metadata(self.issuu_document_url) self.issuu_document_username = metadata.get("username") self.issuu_document_name = metadata.get("docname") self.issuu_config_id = metadata.get("configid") if self.issuu_document_username and self.issuu_document_name: response = urlopen( "http://search.issuu.com/api/2_0/document?q=docname:%s&username=%s" % (self.issuu_document_name, self.issuu_document_username), timeout=timeout) status = response.getcode() body = response.read() if status < 200 or status > 299: raise IssuuSearchAPIError(body) data = loads(body) try: self.issuu_document_id = \ data["response"]["docs"][0]["documentId"] except (KeyError, IndexError): self.issuu_document_id = None if self.issuu_config_id is None: url = Location(self.issuu_document_url) url.query_string.update(e=0) response = urlopen(url.get_url(), timeout=timeout) status = response.getcode() body = response.read() if status >= 200 and status <= 299: url = Location(response.geturl()) issuu_config_id = url.query_string.get("e") if issuu_config_id: self.issuu_config_id = issuu_config_id[0]
Publishable.members_order += ["open_graph_enabled", "open_graph_type"] Publishable.add_member( schema.Boolean("open_graph_enabled", required=True, default=True, listed_by_default=False, member_group="meta.open_graph")) Publishable.add_member( schema.Reference("open_graph_type", type=OpenGraphType, required=Publishable["open_graph_enabled"], related_end=schema.Collection(block_delete=True), default=schema.DynamicDefault( lambda: OpenGraphType.get_instance(code="article")), indexed=True, listed_by_default=False, member_group="meta.open_graph", edit_control=display_factory( "cocktail.html.DropdownSelector", grouping=lambda type: type.category))) def _get_publishable_properties(self): properties = { "og:title": translations(self), "og:type": self.open_graph_type.code, "og:url": self.get_uri(host=".") }