class BillingExportersBrick(Brick): id_ = Brick.generate_id('billing', 'exporters') verbose_name = _('Exporters') template_name = 'billing/bricks/exporters.html' dependencies = (ExporterConfigItem,) configurable = False # permission = 'billing' permissions = 'billing' def detailview_display(self, context): items = [*ExporterConfigItem.objects.all()] sort_key = collator.sort_key items.sort(key=lambda item: sort_key(str(item.content_type))) manager = BillingExportEngineManager() for conf_item in items: conf_item.exporter = manager.exporter( engine_id=conf_item.engine_id, flavour_id=conf_item.flavour_id, model=conf_item.content_type.model_class(), ) return self._render(self.get_template_context( context, config_items=items, ))
def test_instance_block(self): self.login() class TestInstanceBlock(Brick): id_ = InstanceBrickConfigItem.generate_base_id('creme_core', 'invalid_id') brick_entity = CremeEntity.objects.create(user=self.user) generate_id = InstanceBrickConfigItem.generate_id self.assertRaises(ValueError, generate_id, TestInstanceBlock, brick_entity, 'foo#bar') ibi = InstanceBrickConfigItem( brick_id=generate_id(TestInstanceBlock, brick_entity, ''), entity=brick_entity, ) id_is_specific = InstanceBrickConfigItem.id_is_specific self.assertFalse(id_is_specific(Brick.generate_id('creme_core', 'foobar'))) self.assertTrue(id_is_specific(ibi.brick_id)) brick = ibi.brick self.assertIsInstance(brick, Brick) self.assertFalse(isinstance(brick, TestInstanceBlock)) # Because the class is not registered self.assertEqual('??', brick.verbose_name) # self.assertEqual(brick, ibi.block) errors = [_(u'Unknown type of block (bad uninstall ?)')] self.assertEqual(errors, getattr(brick, 'errors', None)) self.assertEqual(errors, ibi.errors)
class UserSynchronizationDebugBrick(Brick): id_ = Brick.generate_id('activesync', 'user_synchronization_debug') dependencies = (UserSynchronizationHistory, ) verbose_name = u'User synchronization DEBUG' template_name = 'activesync/bricks/sync-debug.html' configurable = False def __init__(self, sync): super(UserSynchronizationDebugBrick, self).__init__() self.debug_data = sync._data['debug'] def detailview_display(self, context): debug = settings.ACTIVE_SYNC_DEBUG if debug: debug_data = self.debug_data xml = debug_data['xml'] debug_info = debug_data['info'] debug_errors = debug_data['errors'] else: xml = debug_info = debug_errors = None return self._render( self.get_template_context( context, ACTIVE_SYNC_DEBUG=debug, xml=xml, debug_info=debug_info, debug_errors=debug_errors, ))
class PatternComponentsBrick(Brick): id_ = Brick.generate_id('commercial', 'pattern_components') dependencies = (ActObjectivePatternComponent, ) verbose_name = _('Components of an Objective Pattern') template_name = 'commercial/bricks/components.html' target_ctypes = (ActObjectivePattern, ) def detailview_display(self, context): pattern = context['object'] flattened_tree = [] def explore_tree(components, deep): for comp in components: comp.deep = deep flattened_tree.append(comp) explore_tree(comp.get_children(), deep + 1) explore_tree(pattern.get_components_tree(), 0) return self._render( self.get_template_context( context, components=flattened_tree, ct_id=get_ct(ActObjectivePatternComponent).id, ))
class OpenStreetMapDetailMapBrick(_DetailMapBrick): id_ = Brick.generate_id('geolocation', 'detail_openstreetmap') verbose_name = _('Addresses on OpenStreetMap ®') template_name = 'geolocation/bricks/osm/detail-map.html' def get_map_settings(self): return get_openstreetmap_settings()
class ButtonMenuBrick(Brick): id_ = Brick.generate_id('creme_config', 'button_menu') dependencies = (ButtonMenuItem, ) verbose_name = 'Button menu configuration' template_name = 'creme_config/bricks/button-menu.html' permission = None # NB: used by the view creme_core.views.blocks.reload_basic() configurable = False def detailview_display(self, context): buttons_map = defaultdict(list) for bmi in ButtonMenuItem.objects.order_by('order'): buttons_map[bmi.content_type_id].append(bmi) build_verbose_names = lambda bm_items: [ str(bmi) for bmi in bm_items if bmi.button_id ] default_buttons = build_verbose_names(buttons_map.pop(None, ())) get_ct = ContentType.objects.get_for_id buttons = [(get_ct(ct_id), build_verbose_names(bm_items)) for ct_id, bm_items in buttons_map.items()] sort_key = collator.sort_key buttons.sort(key=lambda t: sort_key(str(t[0]))) return self._render( self.get_template_context( context, default_buttons=default_buttons, buttons=buttons, ))
class FoobarBrick(self.TestBrick): id_ = Brick.generate_id('creme_core', 'test_bricks_reload_basic04') @self.TestBrick.reloading_info.setter def reloading_info(self, info): nonlocal received_extra_data received_extra_data = info
class MobileSyncConfigBrick(Brick): id_ = Brick.generate_id('activesync', 'mobile_sync_config') # dependencies = () verbose_name = u'Mobile synchronization configuration' # template_name = 'activesync/templatetags/block_mobile_sync_config.html' template_name = 'activesync/bricks/default-config.html' configurable = False permission = 'activesync.can_admin' def detailview_display(self, context): # sv_get = SettingValue.objects.get # server_url = sv_get(key_id=MAPI_SERVER_URL) # server_domain = sv_get(key_id=MAPI_DOMAIN) # server_ssl = sv_get(key_id=MAPI_SERVER_SSL) values = get_default_server_setting_values() # return self._render(self.get_block_template_context( return self._render( self.get_template_context( context, # url=server_url, # domain=server_domain, # ssl=server_ssl, url=values['url'], domain=values['domain'], ssl=values['ssl'], # # update_url='/creme_core/blocks/reload/basic/%s/' % self.id_, # update_url=reverse('creme_core__reload_blocks', args=(self.id_,)), ))
class GoogleFilteredMapBrick(_FilteredMapBrick): id_ = Brick.generate_id('geolocation', 'filtered_google_maps') verbose_name = _('Filtered addresses on Google Maps ®') template_name = 'geolocation/bricks/google/filtered-map.html' def get_api_key(self): return get_google_api_key()
class OpenStreetMapFilteredMapBrick(_FilteredMapBrick): id_ = Brick.generate_id('geolocation', 'filtered_openstreetmap') verbose_name = _('Filtered addresses on OpenStreetMap ®') template_name = 'geolocation/bricks/osm/filtered-map.html' def get_map_settings(self): return get_openstreetmap_settings()
class OppTargetBrick(Brick): id_ = Brick.generate_id('opportunities', 'target') verbose_name = _('Target and source') dependencies = (Opportunity, Organisation, Relation) relation_type_deps = (constants.REL_SUB_TARGETS, ) template_name = 'opportunities/bricks/target.html' target_ctypes = (Opportunity, ) def __init__(self): super().__init__() self.display_source = display_source = (len( Organisation.objects.filter_managed_by_creme()) > 1) if display_source: self.relation_type_deps += (constants.REL_OBJ_EMIT_ORGA, ) def detailview_display(self, context): return self._render( self.get_template_context( context, # NB: we do not use .count() in order to use/fill the QuerySet # cache ; it will probably be used several times in the same # page (and if not, this query should be small). display_source=self.display_source, ))
class GoogleNeighboursMapBrick(_MapBrick): id_ = Brick.generate_id('geolocation', 'google_whoisaround') dependencies = (Address, GeoAddress,) verbose_name = _('Neighbours on Google Maps ®') template_name = 'geolocation/bricks/google/neighbours-map.html' target_ctypes = (Contact, Organisation) # Specific use case # Add a new "ungeolocatable" # the person bloc will show an error message # this bloc will show an empty select # edit this address with a geolocatable address # the person block is reloaded and the address is asynchronously geocoded # This block is reloaded in the same time and the address has no info yet. def detailview_display(self, context): entity = context['object'] return self._render(self.get_template_context( context, ref_addresses=self.get_addresses_as_dict(entity), address_filters=self.get_filter_choices(context['user'], Contact, Organisation, ), radius=get_radius(), maps_blockid=GoogleDetailMapBrick.id_, google_api_key=get_google_api_key(), # TODO: factorise ))
class GoogleDetailMapBrick(_DetailMapBrick): id_ = Brick.generate_id('geolocation', 'detail_google_maps') verbose_name = _('Addresses on Google Maps ®') template_name = 'geolocation/bricks/google/detail-map.html' def get_api_key(self): return get_google_api_key()
class FoobarBrick(self.TestBrick): id_ = Brick.generate_id('creme_core', 'test_bricks_reload_detailview06') @self.TestBrick.reloading_info.setter def reloading_info(self, info): received_extra_data.append(info)
class PollFormLinesBrick(Brick): id_ = Brick.generate_id('polls', 'pollform_lines') verbose_name = _('Form lines') dependencies = (PollFormLine, ) template_name = 'polls/bricks/pform-lines.html' target_ctypes = (PollForm, ) @staticmethod def _build_title(nodes): section_count = 0 question_count = 0 for node in nodes: if node.is_section: section_count += 1 else: question_count += 1 def question_label(): return ngettext( '{count} Question', '{count} Questions', question_count, ).format(count=question_count) def section_label(): return ngettext( '{count} Section', '{count} Sections', section_count, ).format(count=section_count) if section_count and question_count: # TODO: unit test return gettext('{questions} and {sections}').format( questions=question_label(), sections=section_label(), ) elif section_count: return section_label() elif question_count: return question_label() return gettext('Questions') def detailview_display(self, context): pform = context['object'] nodes = SectionTree(pform) PollFormLine.populate_conditions( [node for node in nodes if not node.is_section]) return self._render( self.get_template_context( context, nodes=nodes, title=self._build_title(nodes), style=NodeStyle(), ))
class FooBrick(Brick): id_ = Brick.generate_id( 'creme_core', 'CremeBricksTagsTestCase__brick_test_brick_end') verbose_name = 'Testing purpose' brick_str = '<div>FOO</div>' def detailview_display(self, context): return self.brick_str
class ExportButtonBrick(Brick): id_ = Brick.generate_id('creme_config', 'transfer_buttons') verbose_name = _('Export & import configuration') template_name = 'creme_config/bricks/transfer-buttons.html' configurable = False def detailview_display(self, context): return self._render(self.get_template_context(context))
class OpenStreetMapNeighboursMapBrick(_NeighboursMapBrick): id_ = Brick.generate_id('geolocation', 'openstreetmap_whoisaround') verbose_name = _('Neighbours on OpenStreetMap ©') template_name = 'geolocation/bricks/osm/neighbours-map.html' detail_map = OpenStreetMapDetailMapBrick def get_map_settings(self): return get_openstreetmap_settings()
class FoobarBrick3(self.TestBrick): id_ = Brick.generate_id('creme_core', 'test_bricks_reload_detailview02_3') contact = None def detailview_display(self, context): FoobarBrick3.contact = context.get('object') return super().detailview_display(context)
class GoogleNeighboursMapBrick(_NeighboursMapBrick): id_ = Brick.generate_id('geolocation', 'google_whoisaround') verbose_name = _('Neighbours on Google Maps ®') template_name = 'geolocation/bricks/google/neighbours-map.html' detail_map = GoogleDetailMapBrick def get_api_key(self): return get_google_api_key()
class OpportunityCardHatBrick(_RelatedToOpportunity, Brick): id_ = Brick._generate_hat_id('opportunities', 'opportunity_card') verbose_name = _('Card header block') dependencies = [ Opportunity, Organisation, Contact, Relation, *Activities4Card.dependencies, *CommercialActs4Card.dependencies, ] relation_type_deps = [ REL_SUB_EMPLOYED_BY, constants.REL_OBJ_LINKED_CONTACT, *Activities4Card.relation_type_deps, *CommercialActs4Card.relation_type_deps ] template_name = 'opportunities/bricks/opportunity-hat-card.html' displayed_contacts_number = 5 def detailview_display(self, context): opportunity = context['object'] is_hidden = context['fields_configs'].get_4_model( Opportunity).is_fieldname_hidden if apps.is_installed('creme.activities'): from creme.activities import get_activity_model is_neglected = not get_activity_model().objects.future_linked( entity=opportunity, today=context['today'] - timedelta(days=30), ).exists() else: is_neglected = None target = opportunity.target return self._render( self.get_template_context( context, hidden_fields={ fname for fname in ('estimated_sales', 'made_sales') if is_hidden(fname) }, is_neglected=is_neglected, target=target, target_is_organisation=isinstance(target, Organisation), contacts=Paginator( self.get_related_contacts( opportunity=opportunity, rtype_id=constants.REL_SUB_LINKED_CONTACT, ), per_page=self.displayed_contacts_number, ).page(1), activities=Activities4Card.get(context, opportunity), acts=CommercialActs4Card.get(context, opportunity), ))
class GoogleFilteredMapBrick(_MapBrick): id_ = Brick.generate_id('geolocation', 'filtered_google_maps') verbose_name = _('Filtered addresses on Google Maps ®') template_name = 'geolocation/bricks/google/filtered-map.html' def home_display(self, context): return self._render(self.get_template_context( context, address_filters=self.get_filter_choices(context['user'], Contact, Organisation, ), google_api_key=get_google_api_key(), # TODO: factorise ))
class ManagedOrganisationsBrick(PaginatedBrick): id_ = Brick.generate_id('persons', 'managed_organisations') dependencies = (Organisation, ) verbose_name = 'Managed organisations' template_name = 'persons/bricks/managed-organisations.html' configurable = False def detailview_display(self, context): return self._render( self.get_template_context( context, Organisation.objects.filter_managed_by_creme(), ))
class FoobarBrick(self.TestBrick): id_ = Brick.generate_id('creme_core', 'test_bricks_reload_basic05') def detailview_display(self, context): nonlocal error, received_extra_data try: received_extra_data = BricksManager.get( context).get_reloading_info(self) except Exception as e: error = e return super().detailview_display(context)
class CustomFieldsBrick(Brick): id_ = Brick.generate_id('creme_config', 'custom_fields') verbose_name = 'Configuration of custom fields' dependencies = (CustomField, ) template_name = 'creme_config/bricks/custom-fields.html' # permission = None # NB: used by the view creme_core.views.bricks.reload_basic configurable = False def detailview_display(self, context): # NB: we wrap the ContentType instances instead of store extra data in # them because the instances are stored in a global cache, so we do # not want to mutate them. class _ContentTypeWrapper: __slots__ = ('ctype', 'cfields') def __init__(self, ctype, cfields): self.ctype = ctype self.cfields = cfields cfields = CustomField.objects.order_by('id').annotate( enum_count=Count('customfieldenumvalue_set'), ) hide_deleted = BricksManager.get(context).get_state( brick_id=self.id_, user=context['user'], ).get_extra_data(constants.BRICK_STATE_HIDE_DELETED_CFIELDS) if hide_deleted: cfields = cfields.exclude(is_deleted=True) enums_types = {CustomField.ENUM, CustomField.MULTI_ENUM} for cfield in cfields: cfield.is_enum = (cfield.field_type in enums_types) # TODO: templatetag instead ? # ------ cfields_per_ct_id = defaultdict(list) for cfield in cfields: cfields_per_ct_id[cfield.content_type_id].append(cfield) get_ct = ContentType.objects.get_for_id ctypes = [ _ContentTypeWrapper(get_ct(ct_id), ct_cfields) for ct_id, ct_cfields in cfields_per_ct_id.items() ] return self._render( self.get_template_context( context, ctypes=ctypes, hide_deleted=hide_deleted, ))
class CustomFieldsBrick(Brick): id_ = Brick.generate_id('creme_config', 'custom_fields') dependencies = (CustomField, ) verbose_name = 'Configuration of custom fields' template_name = 'creme_config/bricks/custom-fields.html' permission = None # NB: used by the view creme_core.views.bricks.reload_basic configurable = False def detailview_display(self, context): # NB: we wrap the ContentType instances instead of store extra data in # them because the instances are stored in a global cache, so we do # not want to mutate them. class _ContentTypeWrapper: __slots__ = ('ctype', 'cfields') def __init__(self, ctype, cfields): self.ctype = ctype self.cfields = cfields cfields = CustomField.objects.all() # Retrieve & cache Enum values (in order to display them of course) enums_types = {CustomField.ENUM, CustomField.MULTI_ENUM} enums_cfields = [ cfield for cfield in cfields if cfield.field_type in enums_types ] evalues_map = defaultdict(list) for enum_value in CustomFieldEnumValue.objects.filter( custom_field__in=enums_cfields): evalues_map[enum_value.custom_field_id].append(enum_value.value) for enums_cfield in enums_cfields: enums_cfield.enum_values = evalues_map[enums_cfield.id] # ------ cfields_per_ct_id = defaultdict(list) for cfield in cfields: cfields_per_ct_id[cfield.content_type_id].append(cfield) get_ct = ContentType.objects.get_for_id ctypes = [ _ContentTypeWrapper(get_ct(ct_id), ct_cfields) for ct_id, ct_cfields in cfields_per_ct_id.items() ] return self._render(self.get_template_context( context, ctypes=ctypes, ))
class UserSynchronizationResultsBrick(Brick): id_ = Brick.generate_id('activesync', 'user_synchronization_results') dependencies = (UserSynchronizationHistory, ) verbose_name = u'User synchronization results' template_name = 'activesync/bricks/sync-results.html' configurable = False def __init__(self, sync=None, messages=None): super(UserSynchronizationResultsBrick, self).__init__() self.messages = messages or sync.messages() def detailview_display(self, context): return self._render( self.get_template_context(context, all_messages=self.messages))
class GoogleDetailMapBrick(_MapBrick): id_ = Brick.generate_id('geolocation', 'detail_google_maps') verbose_name = _('Addresses on Google Maps ®') template_name = 'geolocation/bricks/google/detail-map.html' target_ctypes = (Contact, Organisation) def detailview_display(self, context): entity = context['object'] addresses = [address for address in self.get_addresses_as_dict(entity) if address.get('content')] return self._render(self.get_template_context( context, addresses=addresses, geoaddresses=addresses, google_api_key=get_google_api_key(), # TODO: factorise ))
class AssetsCharmsMatrixBrick(Brick): id_ = Brick.generate_id('commercial', 'assets_charms_matrix') # dependencies = (CommercialAsset, MarketSegmentCharm,) #useless (custom reload view....) verbose_name = 'Assets / Charms segments matrix' template_name = 'commercial/bricks/assets-charms-matrix.html' configurable = False def detailview_display(self, context): # NB: credentials are OK : we are sure to use the custom reload view if 'strategy' & 'orga' are in the context strategy = context['strategy'] return self._render( self.get_template_context( context, segment_info=strategy.get_segment_descriptions_list(), ))
class ReportFieldsBrick(Brick): id_ = Brick.generate_id('reports', 'fields') dependencies = (Field, ) verbose_name = _('Columns of the report') template_name = 'reports/bricks/fields.html' target_ctypes = (Report, ) def detailview_display(self, context): columns = context['object'].columns return self._render( self.get_template_context( context, columns=columns, expand=any(field.sub_report_id for field in columns), ))