note description: "[ This is the execution of the cms handler request It builds the content to get process to render the output ]" deferred class CMS_EXECUTION inherit CMS_COMMON_API feature {NONE} -- Initialization make (req: WSF_REQUEST; res: WSF_RESPONSE; a_service: like service) do status_code := {HTTP_STATUS_CODE}.ok service := a_service request := req response := res create header.make initialize end initialize do is_front := service.is_front_page (request) has_js := True -- by default it is true, check cookie to see if this is not supported. if attached request.cookie ("has_js") as c_has_js then has_js := c_has_js.same_string ("0") end get_theme controller := service.session_controller (request) create menu_system.make create blocks.make (3) if attached {like message} session_item (pending_messages_session_item_name) as m then message := m end remove_session_item (pending_messages_session_item_name) end feature -- Access service: CMS_SERVICE request: WSF_REQUEST feature {CMS_SESSION_CONTROLER} -- Access: restricted response: WSF_RESPONSE controller: CMS_SESSION_CONTROLER pending_messages_session_item_name: STRING = "cms.pending_messages" -- Session item name to get the pending messages. feature -- Access: CMS site_name: STRING_32 do Result := service.site_name end front_page_url: READABLE_STRING_8 do Result := url ("/", Void) end feature -- Permission frozen has_permissions (lst: detachable ITERABLE [READABLE_STRING_8]): BOOLEAN do if lst = Void then Result := True else Result := across lst as c all has_permission (c.item) end end end frozen has_permission (s: detachable READABLE_STRING_8): BOOLEAN -- Anonymous or Current `user' has permission for `s' --| `s' could be "create page", local u: detachable CMS_USER do if s = Void then Result := True else if s.same_string ("authenticated") then Result := authenticated else u := user if u /= Void and then u.is_admin then Result := True else Result := service.user_has_permission (u, s) end end end end feature -- Status is_front: BOOLEAN has_js: BOOLEAN -- Client has javascript enabled? -- FIXME: not yet implemented is_mobile: BOOLEAN -- Is Client on mobile device? -- FIXME: not yet implemented feature -- Theme theme: CMS_THEME get_theme do create {DEFAULT_CMS_THEME} theme.make (service) end feature -- Access: User authenticated: BOOLEAN do Result := user /= Void end user: detachable CMS_USER do if attached {CMS_USER} session_item ("user") as u then Result := u end end last_user_access_date: detachable DATE_TIME do if attached {DATE_TIME} session_item ("last_access") as dt then Result := dt end end feature -- Element change: user login (u: attached like user; req: WSF_REQUEST) do controller.start_session (req) u.set_last_login_date_now storage.save_user (u) set_user (u) init_last_user_access_date log ("user", "user %"" + u.name + "%" signed in.", 0, user_local_link (u)) end logout (req: WSF_REQUEST) require authenticated do if attached user as u then log ("user", "user %"" + u.name + "%" signed out.", 0, user_local_link (u)) end set_user (Void) controller.start_session (req) end feature -- Logging log (a_category: READABLE_STRING_8; a_message: READABLE_STRING_8; a_level: INTEGER; a_link: detachable CMS_LINK) local l_log: CMS_LOG do create l_log.make (a_category, a_message, a_level, Void) if a_link /= Void then l_log.set_link (a_link) end l_log.set_info (request.http_user_agent) service.storage.save_log (l_log) end feature -- Menu menu_system: CMS_MENU_SYSTEM main_menu: CMS_MENU do Result := menu_system.main_menu end management_menu: CMS_MENU do Result := menu_system.management_menu end navigation_menu: CMS_MENU do Result := menu_system.navigation_menu end user_menu: CMS_MENU do Result := menu_system.user_menu end primary_tabs: CMS_MENU do Result := menu_system.primary_tabs end feature -- Menu: change add_to_main_menu (lnk: CMS_LINK) do if attached {CMS_LOCAL_LINK} lnk as l_local then l_local.get_is_active (request) end main_menu.extend (lnk) end add_to_menu (lnk: CMS_LINK; m: CMS_MENU) do if attached {CMS_LOCAL_LINK} lnk as l_local then l_local.get_is_active (request) end m.extend (lnk) end feature -- Message add_message (a_msg: READABLE_STRING_8; a_category: detachable READABLE_STRING_8) local m: like message do m := message if m = Void then create m.make (a_msg.count + 9) message := m end if a_category /= Void then m.append ("
  • ") else m.append ("
  • ") end m.append (a_msg + "
  • ") end add_notice_message (a_msg: READABLE_STRING_8) do add_message (a_msg, "notice") end add_warning_message (a_msg: READABLE_STRING_8) do add_message (a_msg, "warning") end add_error_message (a_msg: READABLE_STRING_8) do add_message (a_msg, "error") end add_success_message (a_msg: READABLE_STRING_8) do add_message (a_msg, "success") end report_form_errors (fd: CMS_FORM_DATA) require has_error: not fd.is_valid do if attached fd.errors as errs then across errs as err loop if attached err.item as e then if attached e.field as l_field then if attached e.message as e_msg then add_error_message (e_msg) --"Field [" + l_field.name + "] is invalid. " + e_msg) else add_error_message ("Field [" + l_field.name + "] is invalid.") end elseif attached e.message as e_msg then add_error_message (e_msg) end end end end end message: detachable STRING_8 feature -- Blocks formats: CMS_FORMATS once create Result end blocks: ARRAYED_LIST [TUPLE [block: CMS_BLOCK; name: READABLE_STRING_8; region: READABLE_STRING_8]] add_block (b: CMS_BLOCK; a_region: detachable READABLE_STRING_8) do if a_region /= Void then blocks.extend ([b, b.name, a_region]) elseif attached block_region (b) as l_region then blocks.extend ([b, b.name, l_region]) end end block_region (b: CMS_BLOCK): detachable READABLE_STRING_8 local l_name: READABLE_STRING_8 do l_name := b.name if l_name.starts_with ("footer") then Result := "footer" elseif l_name.starts_with ("management") then Result := "first_sidebar" elseif l_name.starts_with ("navigation") then Result := "first_sidebar" elseif l_name.starts_with ("user") then Result := "first_sidebar" else Result := "first_sidebar" end -- FIXME: let the user choose ... end get_blocks local b: CMS_CONTENT_BLOCK s: STRING_8 m: CMS_MENU do m := management_menu if not m.is_empty then add_block (create {CMS_MENU_BLOCK}.make (m), Void) end m := navigation_menu if not m.is_empty then add_block (create {CMS_MENU_BLOCK}.make (m), Void) end m := user_menu if not m.is_empty then add_block (create {CMS_MENU_BLOCK}.make (m), Void) end -- create s.make_empty -- s.append ("This site demonstrates a first implementation of CMS using EWF.%N") -- create b.make ("about", "About", s, formats.plain_text) -- add_block (b, "second_sidebar") create s.make_empty s.append ("Made with EWF") create b.make ("made_with", Void, s, formats.full_html) add_block (b, "footer") service.hook_block_view (Current) end feature -- Access status_code: INTEGER header: WSF_HEADER title: detachable READABLE_STRING_32 -- HTML>head>title value page_title: detachable READABLE_STRING_32 -- Page title additional_page_head_lines: detachable LIST [READABLE_STRING_8] -- HTML>head>...extra lines main_content: detachable STRING_8 redirection: detachable READABLE_STRING_8 feature -- Generation prepare_menu_system (a_menu_system: CMS_MENU_SYSTEM) do across a_menu_system as c loop prepare_links (c.item) end end prepare_links (a_menu: CMS_LINK_COMPOSITE) local to_remove: ARRAYED_LIST [CMS_LINK] do create to_remove.make (0) across a_menu as c loop if attached {CMS_LOCAL_LINK} c.item as lm then if attached lm.permission_arguments as perms and then not has_permissions (perms) then to_remove.force (lm) else -- if lm.permission_arguments is Void , this is permitted lm.get_is_active (request) if attached {CMS_LINK_COMPOSITE} lm as comp then prepare_links (comp) end end elseif attached {CMS_LINK_COMPOSITE} c.item as comp then prepare_links (comp) end end across to_remove as c loop a_menu.remove (c.item) end end prepare (page: CMS_HTML_PAGE) local s: STRING_8 do if attached additional_page_head_lines as l_head_lines then across l_head_lines as hl loop page.head_lines.force (hl.item) end end add_to_main_menu (create {CMS_LOCAL_LINK}.make ("Home", "/")) service.call_menu_alter_hooks (menu_system, Current) prepare_menu_system (menu_system) get_blocks if attached title as l_title then page.set_title (l_title) else page.set_title ("CMS::" + request.path_info) end page.add_to_header_region (top_header_region) page.add_to_header_region (header_region) if attached message as m and then not m.is_empty then page.add_to_content_region ("
    " + m + "
    ") end page.add_to_content_region ("%N") if attached page_title as l_page_title then page.add_to_content_region ("

    "+ l_page_title +"

    %N") end if attached primary_tabs as tabs_menu and then not tabs_menu.is_empty then page.add_to_content_region (theme.menu_html (tabs_menu, True)) end page.add_to_content_region (content_region) -- blocks across blocks as c loop if attached c.item as b_info then create s.make_from_string ("
    ") if attached b_info.block.title as l_title then s.append ("
    " + html_encoded (l_title) + "
    ") end s.append ("
    ") s.append (b_info.block.to_html (theme)) s.append ("
    ") s.append ("
    ") page.add_to_region (s, b_info.region) end end end logo_location: STRING do Result := url ("/theme/logo.png", Void) end top_header_region: STRING_8 do Result := "
    " + html_encoded (site_name) + "
    " Result.append ("
    ") Result.append (theme.menu_html (main_menu, True)) Result.append ("
    ") end header_region: STRING_8 do Result := "" end content_region: STRING_8 do if attached main_content as l_content then Result := l_content else Result := "" debug Result := "No Content" end end end feature -- Head customization add_additional_head_line (s: READABLE_STRING_8; a_allow_duplication: BOOLEAN) local lst: like additional_page_head_lines do lst := additional_page_head_lines if lst = Void then create {ARRAYED_LIST [like additional_page_head_lines.item]} lst.make (1) additional_page_head_lines := lst end if a_allow_duplication or else across lst as c all not c.item.same_string (s) end then lst.extend (s) end end add_style (a_href: STRING; a_media: detachable STRING) local s: STRING_8 do s := "") add_additional_head_line (s, False) end add_javascript_url (a_src: STRING) local s: STRING_8 do s := "" add_additional_head_line (s, False) end add_javascript_content (a_script: STRING) local s: STRING_8 do s := "" add_additional_head_line (s, True) end feature -- Element change set_title (t: like title) do title := t set_page_title (t) end set_page_title (t: like page_title) do page_title := t end set_main_content (s: like main_content) do main_content := s end set_redirection (a_url: like redirection) do if a_url /= Void and then a_url.same_string (request.path_info) and request.is_get_request_method then redirection := Void else redirection := a_url end end feature -- Execution execute do begin process terminate end feature {NONE} -- Execution begin do end process deferred end frozen terminate local cms_page: CMS_HTML_PAGE page: CMS_HTML_PAGE_RESPONSE do create cms_page.make prepare (cms_page) create page.make (theme.page_html (cms_page)) if attached redirection as l_redirection then if attached message as m then set_session_item ("cms.pending_messages", m) end page.set_status_code ({HTTP_STATUS_CODE}.found) page.header.put_location (l_redirection) else page.set_status_code (status_code) end controller.session_commit (page, Current) response.send (page) on_terminated end on_terminated do end feature {NONE} -- Implementation set_user (u: like user) do set_session_item ("user", u) end init_last_user_access_date do set_session_item ("last_access", (create {DATE_TIME}.make_now_utc)) end session_item (k: READABLE_STRING_GENERAL): detachable ANY do Result := controller.session.item (k) end set_session_item (k: READABLE_STRING_GENERAL; v: detachable ANY) do controller.session.remember (v, k) end remove_session_item (k: READABLE_STRING_GENERAL) do controller.session.forget (k) end feature -- Storage storage: CMS_STORAGE do Result := service.storage end feature -- Helper: output user_local_link (u: CMS_USER): CMS_LINK do create {CMS_LOCAL_LINK} Result.make (u.name, user_url (u)) end node_local_link (n: CMS_NODE): CMS_LINK do create {CMS_LOCAL_LINK} Result.make (n.title, node_url (n)) end truncated_string (s: READABLE_STRING_8; nb: INTEGER; a_ellipsis: detachable READABLE_STRING_8): STRING_8 -- Truncated string `s' to `nb' character require a_ellipsis /= Void implies a_ellipsis.count < nb local f: CMS_NO_HTML_FILTER do if s.count <= nb then Result := s.string else create f create Result.make_from_string (s) f.filter (Result) if Result.count > nb then if a_ellipsis /= Void and then not a_ellipsis.is_empty then Result.keep_head (nb - a_ellipsis.count) Result.append (a_ellipsis) else Result.keep_head (nb - 3) Result.append ("...") end end end end feature -- Helper: request non_empty_string_path_parameter (a_name: READABLE_STRING_GENERAL): detachable STRING do if attached {WSF_STRING} request.path_parameter (a_name) as p and then not p.is_empty then Result := p.value end end invariant end