class OrdersDashboardApplication(DashboardApplication): name = None default_permissions = ['is_staff', ] permissions_map = { 'order-list': (['is_staff'], ['partner.dashboard_access']), 'order-stats': (['is_staff'], ['partner.dashboard_access']), 'order-detail': (['is_staff'], ['partner.dashboard_access']), 'order-detail-note': (['is_staff'], ['partner.dashboard_access']), 'order-line-detail': (['is_staff'], ['partner.dashboard_access']), 'order-shipping-address': (['is_staff'], ['partner.dashboard_access']), } order_list_view = get_class('dashboard.orders.views', 'OrderListView') order_detail_view = get_class('dashboard.orders.views', 'OrderDetailView') shipping_address_view = get_class('dashboard.orders.views', 'ShippingAddressUpdateView') line_detail_view = get_class('dashboard.orders.views', 'LineDetailView') order_stats_view = get_class('dashboard.orders.views', 'OrderStatsView') def get_urls(self): urls = [ url(r'^$', self.order_list_view.as_view(), name='order-list'), url(r'^statistics/$', self.order_stats_view.as_view(), name='order-stats'), url(r'^(?P<number>[-\w]+)/$', self.order_detail_view.as_view(), name='order-detail'), url(r'^(?P<number>[-\w]+)/notes/(?P<note_id>\d+)/$', self.order_detail_view.as_view(), name='order-detail-note'), url(r'^(?P<number>[-\w]+)/lines/(?P<line_id>\d+)/$', self.line_detail_view.as_view(), name='order-line-detail'), url(r'^(?P<number>[-\w]+)/shipping-address/$', self.shipping_address_view.as_view(), name='order-shipping-address'), ] return self.post_process_urls(urls)
class BaseCatalogueApplication(Application): name = 'catalogue' detail_view = get_class('catalogue.views', 'ProductDetailView') catalogue_view = get_class('catalogue.views', 'CatalogueView') category_view = get_class('catalogue.views', 'ProductCategoryView') range_view = get_class('offer.views', 'RangeDetailView') def get_urls(self): urlpatterns = super(BaseCatalogueApplication, self).get_urls() urlpatterns += [ url(r'^$', self.catalogue_view.as_view(), name='index'), url(r'^(?P<product_slug>[\w-]*)_(?P<pk>\d+)/$', self.detail_view.as_view(), name='detail'), url(r'^category/(?P<category_slug>[\w-]+(/[\w-]+)*)_(?P<pk>\d+)/$', self.category_view.as_view(), name='category'), # Fallback URL if a user chops of the last part of the URL url(r'^category/(?P<category_slug>[\w-]+(/[\w-]+)*)/$', self.category_view.as_view()), url(r'^ranges/(?P<slug>[\w-]+)/$', self.range_view.as_view(), name='range') ] return self.post_process_urls(urlpatterns)
class VoucherDashboardApplication(DashboardApplication): name = None default_permissions = [ 'is_staff', ] list_view = get_class('dashboard.vouchers.views', 'VoucherListView') create_view = get_class('dashboard.vouchers.views', 'VoucherCreateView') update_view = get_class('dashboard.vouchers.views', 'VoucherUpdateView') delete_view = get_class('dashboard.vouchers.views', 'VoucherDeleteView') stats_view = get_class('dashboard.vouchers.views', 'VoucherStatsView') set_list_view = get_class('dashboard.vouchers.views', 'VoucherSetListView') set_create_view = get_class('dashboard.vouchers.views', 'VoucherSetCreateView') set_update_view = get_class('dashboard.vouchers.views', 'VoucherSetUpdateView') set_detail_view = get_class('dashboard.vouchers.views', 'VoucherSetDetailView') set_download_view = get_class('dashboard.vouchers.views', 'VoucherSetDownloadView') def get_urls(self): urls = [ url(r'^$', self.list_view.as_view(), name='voucher-list'), url(r'^create/$', self.create_view.as_view(), name='voucher-create'), url(r'^update/(?P<pk>\d+)/$', self.update_view.as_view(), name='voucher-update'), url(r'^delete/(?P<pk>\d+)/$', self.delete_view.as_view(), name='voucher-delete'), url(r'^stats/(?P<pk>\d+)/$', self.stats_view.as_view(), name='voucher-stats'), url(r'^sets$', self.set_list_view.as_view(), name='voucher-set-list'), url(r'^sets/create/$', self.set_create_view.as_view(), name='voucher-set-create'), url(r'^sets/update/(?P<pk>\d+)/$', self.set_update_view.as_view(), name='voucher-set-update'), url(r'^sets/(?P<pk>\d+)/$', self.set_detail_view.as_view(), name='voucher-set'), url(r'^sets/(?P<pk>\d+)/download$', self.set_download_view.as_view(), name='voucher-set-download'), ] return self.post_process_urls(urls)
def test_raise_importerror_if_app_raises_importerror(self): """ This tests that Wshop doesn't fall back to using the Wshop catalogue app if the overriding app throws an ImportError. """ apps = list(settings.INSTALLED_APPS) apps[apps.index( 'wshop.apps.catalogue')] = 'tests._site.import_error_app.catalogue' with override_settings(INSTALLED_APPS=apps): with self.assertRaises(ImportError): get_class('catalogue.app', 'CatalogueApplication')
class OfferApplication(Application): name = 'offer' detail_view = get_class('offer.views', 'OfferDetailView') list_view = get_class('offer.views', 'OfferListView') def get_urls(self): urls = [ url(r'^$', self.list_view.as_view(), name='list'), url(r'^(?P<slug>[\w-]+)/$', self.detail_view.as_view(), name='detail'), ] return self.post_process_urls(urls)
class Shop(Application): name = None catalogue_app = get_class('catalogue.app', 'application') customer_app = get_class('customer.app', 'application') basket_app = get_class('basket.app', 'application') checkout_app = get_class('checkout.app', 'application') promotions_app = get_class('promotions.app', 'application') search_app = get_class('search.app', 'application') dashboard_app = get_class('dashboard.app', 'application') offer_app = get_class('offer.app', 'application') password_reset_form = get_class('customer.forms', 'PasswordResetForm') set_password_form = get_class('customer.forms', 'SetPasswordForm') def get_urls(self): urls = [ url(r'^catalogue/', self.catalogue_app.urls), url(r'^basket/', self.basket_app.urls), url(r'^checkout/', self.checkout_app.urls), url(r'^accounts/', self.customer_app.urls), url(r'^search/', self.search_app.urls), url(r'^dashboard/', self.dashboard_app.urls), url(r'^offers/', self.offer_app.urls), # Password reset - as we're using Django's default view functions, # we can't namespace these urls as that prevents # the reverse function from working. url(r'^password-reset/$', login_forbidden(auth_views.password_reset), { 'password_reset_form': self.password_reset_form, 'post_reset_redirect': reverse_lazy('password-reset-done') }, name='password-reset'), url(r'^password-reset/done/$', login_forbidden(auth_views.password_reset_done), name='password-reset-done'), url(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', login_forbidden(auth_views.password_reset_confirm), { 'post_reset_redirect': reverse_lazy('password-reset-complete'), 'set_password_form': self.set_password_form, }, name='password-reset-confirm'), url(r'^password-reset/complete/$', login_forbidden(auth_views.password_reset_complete), name='password-reset-complete'), ] if settings.WSHOP_PROMOTIONS_ENABLED: urls.append(url(r'', self.promotions_app.urls)) return urls
class CheckoutApplication(Application): name = 'checkout' index_view = get_class('checkout.views', 'IndexView') shipping_address_view = get_class('checkout.views', 'ShippingAddressView') user_address_update_view = get_class('checkout.views', 'UserAddressUpdateView') user_address_delete_view = get_class('checkout.views', 'UserAddressDeleteView') shipping_method_view = get_class('checkout.views', 'ShippingMethodView') payment_method_view = get_class('checkout.views', 'PaymentMethodView') payment_details_view = get_class('checkout.views', 'PaymentDetailsView') thankyou_view = get_class('checkout.views', 'ThankYouView') def get_urls(self): urls = [ url(r'^$', self.index_view.as_view(), name='index'), # Shipping/user address views url(r'shipping-address/$', self.shipping_address_view.as_view(), name='shipping-address'), url(r'user-address/edit/(?P<pk>\d+)/$', self.user_address_update_view.as_view(), name='user-address-update'), url(r'user-address/delete/(?P<pk>\d+)/$', self.user_address_delete_view.as_view(), name='user-address-delete'), # Shipping method views url(r'shipping-method/$', self.shipping_method_view.as_view(), name='shipping-method'), # Payment views url(r'payment-method/$', self.payment_method_view.as_view(), name='payment-method'), url(r'payment-details/$', self.payment_details_view.as_view(), name='payment-details'), # Preview and thankyou url(r'preview/$', self.payment_details_view.as_view(preview=True), name='preview'), url(r'thank-you/$', self.thankyou_view.as_view(), name='thank-you'), ] return self.post_process_urls(urls) def get_url_decorator(self, pattern): if not settings.WSHOP_ALLOW_ANON_CHECKOUT: return login_required if pattern.name.startswith('user-address'): return login_required return None
class CommsDashboardApplication(DashboardApplication): name = None default_permissions = [ 'is_staff', ] list_view = get_class('dashboard.communications.views', 'ListView') update_view = get_class('dashboard.communications.views', 'UpdateView') def get_urls(self): urls = [ url(r'^$', self.list_view.as_view(), name='comms-list'), url(r'^(?P<slug>\w+)/$', self.update_view.as_view(), name='comms-update'), ] return self.post_process_urls(urls)
class PromotionsApplication(Application): name = 'promotions' home_view = get_class('promotions.views', 'HomeView') record_click_view = get_class('promotions.views', 'RecordClickView') def get_urls(self): urls = [ url(r'page-redirect/(?P<page_promotion_id>\d+)/$', self.record_click_view.as_view(model=PagePromotion), name='page-click'), url(r'keyword-redirect/(?P<keyword_promotion_id>\d+)/$', self.record_click_view.as_view(model=KeywordPromotion), name='keyword-click'), url(r'^$', self.home_view.as_view(), name='home'), ] return self.post_process_urls(urls)
def test_override_class_loader(self): # Clear lru cache for the class loader get_class_loader.cache_clear() View = get_class('catalogue.views', 'ProductDetailView') self.assertEqual(View, DummyClass) # Clear lru cache for the class loader again get_class_loader.cache_clear()
def get_product_search_handler_class(): """ Determine the search handler to use. Currently only Solr is supported as a search backend, so it falls back to rudimentary category browsing if that isn't enabled. """ # Use get_class to ensure overridability if settings.WSHOP_PRODUCT_SEARCH_HANDLER is not None: return import_string(settings.WSHOP_PRODUCT_SEARCH_HANDLER) if is_solr_supported(): return get_class('catalogue.search_handlers', 'SolrProductSearchHandler') elif is_elasticsearch_supported(): return get_class( 'catalogue.search_handlers', 'ESProductSearchHandler', ) else: return get_class( 'catalogue.search_handlers', 'SimpleProductSearchHandler')
def default_access_fn(user, url_name, url_args=None, url_kwargs=None): """ Given a url_name and a user, this function tries to assess whether the user has the right to access the URL. The application instance of the view is fetched via dynamic imports, and those assumptions will only hold true if the standard Wshop layout is followed. Once the permissions for the view are known, the access logic used by the dashboard decorator is evaluated This function might seem costly, but a simple comparison with DTT did not show any change in response time """ exception = ImproperlyConfigured( "Please follow Wshop's default dashboard app layout or set a " "custom access_fn") if url_name is None: # it's a heading return True # get view module string. try: url = reverse(url_name, args=url_args, kwargs=url_kwargs) except NoReverseMatch: # In Wshop 1.5 this exception was silently ignored which made debugging # very difficult. Now it is being logged and in future the exception will # be propagated. logger.exception('Invalid URL name {}'.format(url_name)) return False view_module = resolve(url).func.__module__ # We can't assume that the view has the same parent module as the app, # as either the app or view can be customised. So we turn the module # string (e.g. 'wshop.apps.dashboard.catalogue.views') into an app # label that can be loaded by get_class (e.g. # 'dashboard.catalogue.app), which then essentially checks # INSTALLED_APPS for the right module to load match = re.search('(dashboard[\w\.]*)\.views$', view_module) if not match: raise exception app_label_str = match.groups()[0] + '.app' try: app_instance = get_class(app_label_str, 'application') except AppNotFoundError: raise exception # handle name-spaced view names if ':' in url_name: view_name = url_name.split(':')[1] else: view_name = url_name permissions = app_instance.get_permissions(view_name) return check_permissions(user, permissions)
class ReviewsApplication(Application): name = None reviews_app = get_class('catalogue.reviews.app', 'application') def get_urls(self): urlpatterns = super(ReviewsApplication, self).get_urls() urlpatterns += [ url(r'^(?P<product_slug>[\w-]*)_(?P<product_pk>\d+)/reviews/', self.reviews_app.urls) ] return self.post_process_urls(urlpatterns)
class ReviewsApplication(DashboardApplication): name = None default_permissions = [ 'is_staff', ] list_view = get_class('dashboard.reviews.views', 'ReviewListView') update_view = get_class('dashboard.reviews.views', 'ReviewUpdateView') delete_view = get_class('dashboard.reviews.views', 'ReviewDeleteView') def get_urls(self): urls = [ url(r'^$', self.list_view.as_view(), name='reviews-list'), url(r'^(?P<pk>\d+)/$', self.update_view.as_view(), name='reviews-update'), url(r'^(?P<pk>\d+)/delete/$', self.delete_view.as_view(), name='reviews-delete'), ] return self.post_process_urls(urls)
class RangeDashboardApplication(DashboardApplication): name = None default_permissions = [ 'is_staff', ] list_view = get_class('dashboard.ranges.views', 'RangeListView') create_view = get_class('dashboard.ranges.views', 'RangeCreateView') update_view = get_class('dashboard.ranges.views', 'RangeUpdateView') delete_view = get_class('dashboard.ranges.views', 'RangeDeleteView') products_view = get_class('dashboard.ranges.views', 'RangeProductListView') reorder_view = get_class('dashboard.ranges.views', 'RangeReorderView') def get_urls(self): urlpatterns = [ url(r'^$', self.list_view.as_view(), name='range-list'), url(r'^create/$', self.create_view.as_view(), name='range-create'), url(r'^(?P<pk>\d+)/$', self.update_view.as_view(), name='range-update'), url(r'^(?P<pk>\d+)/delete/$', self.delete_view.as_view(), name='range-delete'), url(r'^(?P<pk>\d+)/products/$', self.products_view.as_view(), name='range-products'), url(r'^(?P<pk>\d+)/reorder/$', self.reorder_view.as_view(), name='range-reorder'), ] return self.post_process_urls(urlpatterns)
class FlatPageManagementApplication(DashboardApplication): name = None default_permissions = ['is_staff', ] list_view = get_class('dashboard.pages.views', 'PageListView') create_view = get_class('dashboard.pages.views', 'PageCreateView') update_view = get_class('dashboard.pages.views', 'PageUpdateView') delete_view = get_class('dashboard.pages.views', 'PageDeleteView') def get_urls(self): """ Get URL patterns defined for flatpage management application. """ urls = [ url(r'^$', self.list_view.as_view(), name='page-list'), url(r'^create/$', self.create_view.as_view(), name='page-create'), url(r'^update/(?P<pk>[-\w]+)/$', self.update_view.as_view(), name='page-update'), url(r'^delete/(?P<pk>\d+)/$', self.delete_view.as_view(), name='page-delete') ] return self.post_process_urls(urls)
class ReportsApplication(DashboardApplication): name = None default_permissions = [ 'is_staff', ] index_view = get_class('dashboard.reports.views', 'IndexView') def get_urls(self): urls = [ url(r'^$', self.index_view.as_view(), name='reports-index'), ] return self.post_process_urls(urls)
class BasketApplication(Application): name = 'basket' summary_view = get_class('basket.views', 'BasketView') saved_view = get_class('basket.views', 'SavedView') add_view = get_class('basket.views', 'BasketAddView') add_voucher_view = get_class('basket.views', 'VoucherAddView') remove_voucher_view = get_class('basket.views', 'VoucherRemoveView') def get_urls(self): urls = [ url(r'^$', self.summary_view.as_view(), name='summary'), url(r'^add/(?P<pk>\d+)/$', self.add_view.as_view(), name='add'), url(r'^vouchers/add/$', self.add_voucher_view.as_view(), name='vouchers-add'), url(r'^vouchers/(?P<pk>\d+)/remove/$', self.remove_voucher_view.as_view(), name='vouchers-remove'), url(r'^saved/$', login_required(self.saved_view.as_view()), name='saved'), ] return self.post_process_urls(urls)
class SearchApplication(Application): name = 'search' search_view = get_class('search.views', 'FacetedSearchView') search_form = get_class('search.forms', 'SearchForm') def get_urls(self): # The form class has to be passed to the __init__ method as that is how # Haystack works. It's slightly different to normal CBVs. urlpatterns = [ url(r'^$', search_view_factory(view_class=self.search_view, form_class=self.search_form, searchqueryset=self.get_sqs()), name='search'), ] return self.post_process_urls(urlpatterns) def get_sqs(self): """ Return the SQS required by a the Haystack search view """ return facets.base_sqs()
class RequestFactory(BaseRequestFactory): Basket = get_model('basket', 'basket') selector = get_class('partner.strategy', 'Selector')() def request(self, user=None, **request): request = super(RequestFactory, self).request(**request) request.user = user or AnonymousUser() request.session = SessionStore() request._messages = FallbackStorage(request) request.basket = self.Basket() request.basket_hash = None strategy = self.selector.strategy(request=request, user=request.user) request.strategy = request.basket.strategy = strategy return request
def proxy_map(self): return { self.PERCENTAGE: get_class('offer.benefits', 'PercentageDiscountBenefit'), self.FIXED: get_class('offer.benefits', 'AbsoluteDiscountBenefit'), self.MULTIBUY: get_class('offer.benefits', 'MultibuyDiscountBenefit'), self.FIXED_PRICE: get_class('offer.benefits', 'FixedPriceBenefit'), self.SHIPPING_ABSOLUTE: get_class('offer.benefits', 'ShippingAbsoluteDiscountBenefit'), self.SHIPPING_FIXED_PRICE: get_class('offer.benefits', 'ShippingFixedPriceBenefit'), self.SHIPPING_PERCENTAGE: get_class('offer.benefits', 'ShippingPercentageDiscountBenefit') }
class OffersDashboardApplication(DashboardApplication): name = None default_permissions = ['is_staff', ] list_view = get_class('dashboard.offers.views', 'OfferListView') metadata_view = get_class('dashboard.offers.views', 'OfferMetaDataView') condition_view = get_class('dashboard.offers.views', 'OfferConditionView') benefit_view = get_class('dashboard.offers.views', 'OfferBenefitView') restrictions_view = get_class('dashboard.offers.views', 'OfferRestrictionsView') delete_view = get_class('dashboard.offers.views', 'OfferDeleteView') detail_view = get_class('dashboard.offers.views', 'OfferDetailView') def get_urls(self): urls = [ url(r'^$', self.list_view.as_view(), name='offer-list'), # Creation url(r'^new/name-and-description/$', self.metadata_view.as_view(), name='offer-metadata'), url(r'^new/condition/$', self.condition_view.as_view(), name='offer-condition'), url(r'^new/incentive/$', self.benefit_view.as_view(), name='offer-benefit'), url(r'^new/restrictions/$', self.restrictions_view.as_view(), name='offer-restrictions'), # Update url(r'^(?P<pk>\d+)/name-and-description/$', self.metadata_view.as_view(update=True), name='offer-metadata'), url(r'^(?P<pk>\d+)/condition/$', self.condition_view.as_view(update=True), name='offer-condition'), url(r'^(?P<pk>\d+)/incentive/$', self.benefit_view.as_view(update=True), name='offer-benefit'), url(r'^(?P<pk>\d+)/restrictions/$', self.restrictions_view.as_view(update=True), name='offer-restrictions'), # Delete url(r'^(?P<pk>\d+)/delete/$', self.delete_view.as_view(), name='offer-delete'), # Stats url(r'^(?P<pk>\d+)/$', self.detail_view.as_view(), name='offer-detail'), ] return self.post_process_urls(urls)
class RequestFactory(BaseRequestFactory): Basket = get_model('basket', 'basket') selector = get_class('partner.strategy', 'Selector')() def request(self, user=None, basket=None, **request): request = super(RequestFactory, self).request(**request) request.user = user or AnonymousUser() request.session = SessionStore() request._messages = FallbackStorage(request) # Mimic basket middleware request.strategy = self.selector.strategy(request=request, user=request.user) request.basket = basket or self.Basket() request.basket.strategy = request.strategy request.basket_hash = Signer().sign(basket.pk) if basket else None request.cookies_to_delete = [] return request
class ShippingDashboardApplication(DashboardApplication): name = None default_permissions = ['is_staff'] weight_method_list_view = get_class( 'dashboard.shipping.views', 'WeightBasedListView') weight_method_create_view = get_class( 'dashboard.shipping.views', 'WeightBasedCreateView') weight_method_edit_view = get_class( 'dashboard.shipping.views', 'WeightBasedUpdateView') weight_method_delete_view = get_class( 'dashboard.shipping.views', 'WeightBasedDeleteView') # This doubles as the weight_band create view weight_method_detail_view = get_class( 'dashboard.shipping.views', 'WeightBasedDetailView') weight_band_edit_view = get_class( 'dashboard.shipping.views', 'WeightBandUpdateView') weight_band_delete_view = get_class( 'dashboard.shipping.views', 'WeightBandDeleteView') def get_urls(self): urlpatterns = [ url(r'^weight-based/$', self.weight_method_list_view.as_view(), name='shipping-method-list'), url(r'^weight-based/create/$', self.weight_method_create_view.as_view(), name='shipping-method-create'), url(r'^weight-based/(?P<pk>\d+)/$', self.weight_method_detail_view.as_view(), name='shipping-method-detail'), url(r'^weight-based/(?P<pk>\d+)/edit/$', self.weight_method_edit_view.as_view(), name='shipping-method-edit'), url(r'^weight-based/(?P<pk>\d+)/delete/$', self.weight_method_delete_view.as_view(), name='shipping-method-delete'), url(r'^weight-based/(?P<method_pk>\d+)/bands/(?P<pk>\d+)/$', self.weight_band_edit_view.as_view(), name='shipping-method-band-edit'), url(r'^weight-based/(?P<method_pk>\d+)/bands/(?P<pk>\d+)/delete/$', self.weight_band_delete_view.as_view(), name='shipping-method-band-delete'), ] return self.post_process_urls(urlpatterns)
def test_load_formset_new_destination(self): BaseBasketLineFormSet = get_class('basket.formsets', 'BaseBasketLineFormSet') self.assertEqual('wshop.apps.basket.formsets', BaseBasketLineFormSet.__module__) StockRecordFormSet = get_class('dashboard.catalogue.formsets', 'StockRecordFormSet') self.assertEqual('wshop.apps.dashboard.catalogue.formsets', StockRecordFormSet.__module__) OrderedProductFormSet = get_class('dashboard.promotions.formsets', 'OrderedProductFormSet') OrderedProductForm = get_class('dashboard.promotions.forms', 'OrderedProductForm') self.assertTrue( isinstance(OrderedProductFormSet().forms[0], OrderedProductForm)) LineFormset = get_class('wishlists.formsets', 'LineFormset') WishListLineForm = get_class('wishlists.forms', 'WishListLineForm') self.assertTrue( isinstance( LineFormset(instance=self.wishlist).forms[0], WishListLineForm))
class UserManagementApplication(DashboardApplication): name = None default_permissions = ['is_staff', ] index_view = get_class('dashboard.users.views', 'IndexView') user_detail_view = get_class('dashboard.users.views', 'UserDetailView') password_reset_view = get_class('dashboard.users.views', 'PasswordResetView') alert_list_view = get_class('dashboard.users.views', 'ProductAlertListView') alert_update_view = get_class('dashboard.users.views', 'ProductAlertUpdateView') alert_delete_view = get_class('dashboard.users.views', 'ProductAlertDeleteView') def get_urls(self): urls = [ url(r'^$', self.index_view.as_view(), name='users-index'), url(r'^(?P<pk>-?\d+)/$', self.user_detail_view.as_view(), name='user-detail'), url(r'^(?P<pk>-?\d+)/password-reset/$', self.password_reset_view.as_view(), name='user-password-reset'), # Alerts url(r'^alerts/$', self.alert_list_view.as_view(), name='user-alert-list'), url(r'^alerts/(?P<pk>-?\d+)/delete/$', self.alert_delete_view.as_view(), name='user-alert-delete'), url(r'^alerts/(?P<pk>-?\d+)/update/$', self.alert_update_view.as_view(), name='user-alert-update'), ] return self.post_process_urls(urls)
def test_load_formset_old_destination(self): BaseBasketLineFormSet = get_class('basket.forms', 'BaseBasketLineFormSet') self.assertEqual('wshop.apps.basket.formsets', BaseBasketLineFormSet.__module__) StockRecordFormSet = get_class('dashboard.catalogue.forms', 'StockRecordFormSet') self.assertEqual('wshop.apps.dashboard.catalogue.formsets', StockRecordFormSet.__module__) OrderedProductFormSet = get_class('dashboard.promotions.forms', 'OrderedProductFormSet') OrderedProductForm = get_class('dashboard.promotions.forms', 'OrderedProductForm') # Since OrderedProductFormSet created with metaclass, it has __module__ # attribute pointing to the Django module. Thus, we test if formset was # loaded correctly by initiating class instance and checking its forms. self.assertTrue( isinstance(OrderedProductFormSet().forms[0], OrderedProductForm)) LineFormset = get_class('wishlists.forms', 'LineFormset') WishListLineForm = get_class('wishlists.forms', 'WishListLineForm') self.assertTrue( isinstance( LineFormset(instance=self.wishlist).forms[0], WishListLineForm))
from collections import defaultdict from django import forms from django.conf import settings from django.forms.widgets import Input from django.utils.translation import ugettext_lazy as _ from haystack.forms import FacetedSearchForm from wshop.core.loading import get_class is_solr_supported = get_class('search.features', 'is_solr_supported') class SearchInput(Input): """ Defining a search type widget This is an HTML5 thing and works nicely with Safari, other browsers default back to using the default "text" type """ input_type = 'search' # Build a dict of valid queries VALID_FACET_QUERIES = defaultdict(list) for facet in settings.WSHOP_SEARCH_FACETS['queries'].values(): field_name = "%s_exact" % facet['field'] queries = [t[1] for t in facet['queries']] VALID_FACET_QUERIES[field_name].extend(queries)
from django.utils.functional import cached_property from django.utils.html import strip_tags from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ from django.utils.translation import get_language, pgettext_lazy from treebeard.mp_tree import MP_Node from wshop.core.loading import get_class, get_classes, get_model from wshop.core.utils import slugify from wshop.core.validators import non_python_keyword from wshop.models.fields import AutoSlugField, NullCharField from wshop.models.fields.slugfield import SlugField ProductManager, BrowsableProductManager = get_classes( 'catalogue.managers', ['ProductManager', 'BrowsableProductManager']) ProductAttributesContainer = get_class('catalogue.product_attributes', 'ProductAttributesContainer') Selector = get_class('partner.strategy', 'Selector') @python_2_unicode_compatible class AbstractProductClass(models.Model): """ Used for defining options and attributes for a subset of products. E.g. Books, DVDs and Toys. A product can only belong to one product class. At least one product class must be created when setting up a new Wshop deployment. Not necessarily equivalent to top-level categories but usually will be. """ name = models.CharField(_('Name'), max_length=128)
from django.conf import settings from django.http import Http404, HttpResponseForbidden from django.template.response import TemplateResponse from django.utils.translation import ugettext_lazy as _ from django.views.generic import ListView from wshop.core.loading import get_class ReportForm = get_class('dashboard.reports.forms', 'ReportForm') GeneratorRepository = get_class('dashboard.reports.utils', 'GeneratorRepository') class IndexView(ListView): template_name = 'dashboard/reports/index.html' paginate_by = settings.WSHOP_DASHBOARD_ITEMS_PER_PAGE context_object_name = 'objects' report_form_class = ReportForm generator_repository = GeneratorRepository def _get_generator(self, form): code = form.cleaned_data['report_type'] repo = self.generator_repository() generator_cls = repo.get_generator(code) if not generator_cls: raise Http404() download = form.cleaned_data['download'] formatter = 'CSV' if download else 'HTML'