1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

# -*- coding: utf-8 -*-

"""A collection of functions for Page CMS"""

import sys, re, logging, pprint, traceback

from django.conf import settings as django_settings

from django.template import TemplateDoesNotExist

from django.template import loader, Context, RequestContext

from django.core.cache import cache

from pages import settings

from pages.http import get_request_mock, get_language_from_request

 

def get_context_mock():

    """return a mockup dictionnary to use in get_placeholders."""

    context = {'current_page':None}

    if settings.PAGE_EXTRA_CONTEXT:

        context.update(settings.PAGE_EXTRA_CONTEXT())

    return context

 

def get_placeholders(template_name):

    """Return a list of PlaceholderNode found in the given template.

 

    :param template_name: the name of the template file

    """

    try:

        temp = loader.get_template(template_name)

    except TemplateDoesNotExist:

        return []

 

    request = get_request_mock()

    context = get_context_mock()

    # I need to render the template in order to extract

    # placeholder tags

    temp.render(RequestContext(request, context))

    plist, blist = [], []

    _placeholders_recursif(temp.nodelist, plist, blist)

    return plist

 

def _placeholders_recursif(nodelist, plist, blist):

    """Recursively search into a template node list for PlaceholderNode

    node."""

    # I needed to import make this lazy import to make the doc compile

    from django.template.loader_tags import BlockNode

 

    for node in nodelist:

 

        # extends node

        if hasattr(node, 'parent_name'):

            _placeholders_recursif(node.get_parent(Context()).nodelist,

                                                        plist, blist)

        # include node

        elif hasattr(node, 'template'):

            _placeholders_recursif(node.template.nodelist, plist, blist)

 

        # It's a placeholder

        if hasattr(node, 'page') and hasattr(node, 'parsed') and \

                hasattr(node, 'as_varname') and hasattr(node, 'name'):

            already_in_plist = False

            for pl in plist:

                if pl.name == node.name:

                    already_in_plist = True

            if not already_in_plist:

                if len(blist):

                    node.found_in_block = blist[len(blist)-1]

                plist.append(node)

            node.render(Context())

 

        for key in ('nodelist', 'nodelist_true', 'nodelist_false'):

            if isinstance(node, BlockNode):

                # delete placeholders found in a block of the same name

                for index, pl in enumerate(plist):

                    if pl.found_in_block and \

                            pl.found_in_block.name == node.name \

                            and pl.found_in_block != node:

                        del plist[index]

                blist.append(node)

 

            if hasattr(node, key):

                try:

                    _placeholders_recursif(getattr(node, key), plist, blist)

                except:

                    pass

            if isinstance(node, BlockNode):

                blist.pop()

 

def has_page_add_permission(request, page=None):

    """Return true if the current user has permission to add a new page.

 

    :param page: not used

    """

    if not settings.PAGE_PERMISSION:

        return True

    else:

        from pages.models import PagePermission

        permission = PagePermission.objects.get_page_id_list(request.user)

        if permission == "All":

            return True

        # the user has the right to add a page under a page he control

        target = request.GET.get('target', None)

        if target is not None:

            try:

                target = int(target)

                if target in permission:

                    return True

            except:

                pass

    return False

 

 

def normalize_url(url):

    """Return a normalized url with trailing and without leading slash.

 

     >>> normalize_url(None)

     '/'

     >>> normalize_url('/')

     '/'

     >>> normalize_url('/foo/bar')

     '/foo/bar'

     >>> normalize_url('foo/bar')

     '/foo/bar'

     >>> normalize_url('/foo/bar/')

     '/foo/bar'

    """

    if not url or len(url)==0:

        return '/'

    if not url.startswith('/'):

        url = '/' + url

    if len(url)>1 and url.endswith('/'):

        url = url[0:len(url)-1]

    return url

 

PAGE_CLASS_ID_REGEX = re.compile('page_([0-9]+)')

 

def filter_link(content, page, language, content_type):

    """Transform the HTML link href to point to the targeted page

    absolute URL.

 

     >>> filter_link('<a class="page_1">hello</a>', page, 'en-us', body)

     '<a href="/pages/page-1" class="page_1">hello</a>'

    """

    if not settings.PAGE_LINK_FILTER:

        return content

    if content_type in ('title', 'slug'):

        return content

    from BeautifulSoup import BeautifulSoup

    tree = BeautifulSoup(content)

    tags = tree.findAll('a')

    if len(tags) == 0:

        return content

    for tag in tags:

        tag_class = tag.get('class', False)

        if tag_class:

            # find page link with class 'page_ID'

            result = PAGE_CLASS_ID_REGEX.search(content)

            if result and result.group:

                try:

                    # TODO: try the cache before fetching the Page object

                    from pages.models import Page

                    target_page = Page.objects.get(pk=int(result.group(1)))

                    tag['href'] = target_page.get_url_path(language)

                except Page.DoesNotExist:

                    cache.set(Page.PAGE_BROKEN_LINK_KEY % page.id, True)

                    tag['class'] = 'pagelink_broken'

    return unicode(tree)