Commit 9398a6781686d7a8d5e27a2f364c59d903fbd606
Committed by
Matheus de Sousa Faria
1 parent
7daa556e
Exists in
profile_integration
New Widget concept
Signed-off-by: Charles Oliveira <18oliveira.charles@gmail.com> Signed-off-by: Gustavo Jaruga <darksshades@gmail.com>
Showing
12 changed files
with
334 additions
and
72 deletions
Show diff stats
colab/accounts/templates/accounts/user_update_form.html
1 | {% extends "base.html" %} | 1 | {% extends "base.html" %} |
2 | -{% load i18n gravatar %} | 2 | +{% load i18n gravatar plugins %} |
3 | 3 | ||
4 | {% block head_js %} | 4 | {% block head_js %} |
5 | <script> | 5 | <script> |
@@ -102,6 +102,14 @@ $(function() { | @@ -102,6 +102,14 @@ $(function() { | ||
102 | </script> | 102 | </script> |
103 | {% endblock %} | 103 | {% endblock %} |
104 | 104 | ||
105 | +{% block head %} | ||
106 | + {{ block.super }} | ||
107 | + | ||
108 | + {% for widget in widgets %} | ||
109 | + {{ widget.get_header }} | ||
110 | + {% endfor %} | ||
111 | + | ||
112 | +{% endblock %} | ||
105 | 113 | ||
106 | {% block main-content %} | 114 | {% block main-content %} |
107 | 115 | ||
@@ -113,88 +121,123 @@ $(function() { | @@ -113,88 +121,123 @@ $(function() { | ||
113 | <h3>{% gravatar user_.email 50 %} {{ user_.get_full_name }} ({{ user_.username }})</h3> | 121 | <h3>{% gravatar user_.email 50 %} {{ user_.get_full_name }} ({{ user_.username }})</h3> |
114 | <a href="https://gravatar.com" target="_blank"> | 122 | <a href="https://gravatar.com" target="_blank"> |
115 | {% trans "Change your avatar at Gravatar.com" %} | 123 | {% trans "Change your avatar at Gravatar.com" %} |
116 | - </a> | 124 | + </a>{{ lala }} |
117 | </div> | 125 | </div> |
118 | <br> | 126 | <br> |
119 | <br> | 127 | <br> |
120 | 128 | ||
121 | - <form method="post"> | ||
122 | - {% csrf_token %} | ||
123 | - | ||
124 | - <div class="row"> | ||
125 | - <div class="col-lg-8 col-md-7 col-sm-12 col-xm-12"> | ||
126 | - {% for field in form %} | ||
127 | - <div class="col-lg-6 col-md-6 col-sm-12 col-xm-12"> | ||
128 | - <div class="form-group{% if field.field.required %} required{% endif %}{% if field.errors %} alert alert-danger has-error{% endif %}"> | ||
129 | - <label for="{{ field.name }}" class="control-label"> | ||
130 | - {{ field.label }} | ||
131 | - </label> | ||
132 | - {{ field }} | ||
133 | - {{ field.errors }} | ||
134 | - </div> | ||
135 | - </div> | ||
136 | - {% endfor %} | ||
137 | - </div> | 129 | + <!-- Start of navs --> |
130 | + <ul class="nav nav-tabs"> | ||
131 | + <li class="active"><a data-toggle="pill" href="#profile">Profile</a></li> | ||
132 | + {% for widget in widgets %} | ||
133 | + <li> | ||
134 | + <a data-toggle="pill" href="#{{ widget.identifier }}">{{ widget.name }}</a> | ||
135 | + </li> | ||
136 | + {% endfor %} | ||
137 | + </ul> | ||
138 | + <!-- End of navs --> | ||
139 | + <style type="text/css"> | ||
140 | + .tab-pane{ | ||
141 | + border: 1px solid #DDD; | ||
142 | + border-top: none; | ||
143 | + padding: 10px; | ||
144 | + } | ||
138 | 145 | ||
139 | - <div class="col-lg-4 col-md-5 col-sm-12 col-xm-12"> | ||
140 | - <div class="panel panel-default"> | ||
141 | - <div class="panel-heading"> | ||
142 | - <h3 class="panel-title">{% trans "Emails" %}</h3> | ||
143 | - </div> | ||
144 | - <div class="panel-body"> | ||
145 | - <ul class="unstyled-list emails"> | ||
146 | - {% for email in user_.emails.iterator %} | ||
147 | - <li> | ||
148 | - {% gravatar user_.email 30 %} | ||
149 | - <span class="email-address">{{ email.address }}</span> | ||
150 | - {% if email.address == user_.email %} | ||
151 | - <span class="label label-success">{% trans "Primary" %}</span> | ||
152 | - {% else %} | ||
153 | - <div class="text-right"> | ||
154 | - <button class="btn btn-default set-primary" data-loading-text="{% trans 'Setting...' %}">{% trans "Set as Primary" %}</button> | ||
155 | - <button class="btn btn-danger delete-email" data-loading-text="{% trans 'Deleting...' %}">{% trans "Delete" %}</button> | ||
156 | - </div> | ||
157 | - {% endif %} | ||
158 | - <hr /> | ||
159 | - </li> | 146 | + .nav-tabs a:focus { |
147 | + outline: none; | ||
148 | + } | ||
149 | + </style> | ||
150 | + <div class="tab-content"> | ||
151 | + <div id="profile" class="tab-pane fade"> | ||
152 | + <form method="post"> | ||
153 | + {% csrf_token %} | ||
154 | + | ||
155 | + <div class="row"> | ||
156 | + <div class="col-lg-8 col-md-7 col-sm-12 col-xm-12"> | ||
157 | + {% for field in form %} | ||
158 | + <div class="col-lg-6 col-md-6 col-sm-12 col-xm-12"> | ||
159 | + <div class="form-group{% if field.field.required %} required{% endif %}{% if field.errors %} alert alert-danger has-error{% endif %}"> | ||
160 | + <label for="{{ field.name }}" class="control-label"> | ||
161 | + {{ field.label }} | ||
162 | + </label> | ||
163 | + {{ field }} | ||
164 | + {{ field.errors }} | ||
165 | + </div> | ||
166 | + </div> | ||
160 | {% endfor %} | 167 | {% endfor %} |
161 | - {% for email in user_.emails_not_validated.iterator %} | ||
162 | - <li> | ||
163 | - {% gravatar user_.email 30 %} | ||
164 | - <span class="email-address">{{ email.address }}</span> | ||
165 | - <div class="text-right"> | ||
166 | - <button class="btn btn-default verify-email" data-loading-text="{% trans 'Sending verification...' %}"><span class="icon-warning-sign"></span> {% trans "Verify" %}</button> | ||
167 | - <button class="btn btn-danger delete-email">{% trans "Delete" %}</button> | 168 | + </div> |
169 | + | ||
170 | + <div class="col-lg-4 col-md-5 col-sm-12 col-xm-12"> | ||
171 | + <div class="panel panel-default"> | ||
172 | + <div class="panel-heading"> | ||
173 | + <h3 class="panel-title">{% trans "Emails" %}</h3> | ||
174 | + </div> | ||
175 | + <div class="panel-body"> | ||
176 | + <ul class="unstyled-list emails"> | ||
177 | + {% for email in user_.emails.iterator %} | ||
178 | + <li> | ||
179 | + {% gravatar user_.email 30 %} | ||
180 | + <span class="email-address">{{ email.address }}</span> | ||
181 | + {% if email.address == user_.email %} | ||
182 | + <span class="label label-success">{% trans "Primary" %}</span> | ||
183 | + {% else %} | ||
184 | + <div class="text-right"> | ||
185 | + <button class="btn btn-default set-primary" data-loading-text="{% trans 'Setting...' %}">{% trans "Set as Primary" %}</button> | ||
186 | + <button class="btn btn-danger delete-email" data-loading-text="{% trans 'Deleting...' %}">{% trans "Delete" %}</button> | ||
187 | + </div> | ||
188 | + {% endif %} | ||
189 | + <hr /> | ||
190 | + </li> | ||
191 | + {% endfor %} | ||
192 | + {% for email in user_.emails_not_validated.iterator %} | ||
193 | + <li> | ||
194 | + {% gravatar user_.email 30 %} | ||
195 | + <span class="email-address">{{ email.address }}</span> | ||
196 | + <div class="text-right"> | ||
197 | + <button class="btn btn-default verify-email" data-loading-text="{% trans 'Sending verification...' %}"><span class="icon-warning-sign"></span> {% trans "Verify" %}</button> | ||
198 | + <button class="btn btn-danger delete-email">{% trans "Delete" %}</button> | ||
199 | + </div> | ||
200 | + <hr /> | ||
201 | + </li> | ||
202 | + {% endfor %} | ||
203 | + </ul> | ||
204 | + <div class="form-group"> | ||
205 | + <label for="new_email">{% trans "Add another email address:" %}</label> | ||
206 | + <input id="new_email" name="new_email" class="form-control" autocomplete="off" /> | ||
168 | </div> | 207 | </div> |
169 | - <hr /> | ||
170 | - </li> | ||
171 | - {% endfor %} | ||
172 | - </ul> | ||
173 | - <div class="form-group"> | ||
174 | - <label for="new_email">{% trans "Add another email address:" %}</label> | ||
175 | - <input id="new_email" name="new_email" class="form-control" autocomplete="off" /> | 208 | + <button class="btn btn-primary pull-right" id="add-email">{% trans "Add" %}</button> |
209 | + </div> | ||
176 | </div> | 210 | </div> |
177 | - <button class="btn btn-primary pull-right" id="add-email">{% trans "Add" %}</button> | ||
178 | </div> | 211 | </div> |
179 | - </div> | ||
180 | - </div> | ||
181 | - <div class="col-lg-4 col-md-5 col-sm-12 col-xm-12"> | ||
182 | - <div class="panel panel-default"> | ||
183 | - <div class="panel-heading"> | ||
184 | - <h3 class="panel-title"> | ||
185 | - {% trans 'Change Password' %} | ||
186 | - </h3> | 212 | + <div class="col-lg-4 col-md-5 col-sm-12 col-xm-12"> |
213 | + <div class="panel panel-default"> | ||
214 | + <div class="panel-heading"> | ||
215 | + <h3 class="panel-title"> | ||
216 | + {% trans 'Change Password' %} | ||
217 | + </h3> | ||
218 | + </div> | ||
219 | + <div class="panel-body"> | ||
220 | + <a href="{% url 'password_change' %}" class="btn btn-default btn-primary pull-right btn-block">{% trans "Change Password" %}</a> | ||
221 | + </div> | ||
222 | + </div> | ||
187 | </div> | 223 | </div> |
188 | - <div class="panel-body"> | ||
189 | - <a href="{% url 'password_change' %}" class="btn btn-default btn-primary pull-right btn-block">{% trans "Change Password" %}</a> | 224 | + </div> |
225 | + <div class="row"> | ||
226 | + <div class="submit"> | ||
227 | + <button type="submit" class="btn btn-primary btn-lg btn-block">{% trans "Update" %}</button> | ||
190 | </div> | 228 | </div> |
191 | </div> | 229 | </div> |
192 | - </div> | 230 | + </form> |
231 | + </div> | ||
232 | + <div id="code" class="tab-pane fade in active"> | ||
233 | + {% content_xpto %} | ||
193 | </div> | 234 | </div> |
194 | - <div class="row"> | ||
195 | - <div class="submit"> | ||
196 | - <button type="submit" class="btn btn-primary btn-lg btn-block">{% trans "Update" %}</button> | ||
197 | - </div> | 235 | + <div id="social" class="tab-pane fade"> |
236 | + <p>Some content in menu 2.</p> | ||
198 | </div> | 237 | </div> |
199 | - </form> | 238 | + </div> |
239 | + | ||
240 | + | ||
241 | + | ||
242 | + | ||
200 | {% endblock %} | 243 | {% endblock %} |
colab/accounts/views.py
@@ -15,6 +15,7 @@ from colab.super_archives.models import (EmailAddress, | @@ -15,6 +15,7 @@ from colab.super_archives.models import (EmailAddress, | ||
15 | EmailAddressValidation) | 15 | EmailAddressValidation) |
16 | from colab.search.utils import get_collaboration_data, get_visible_threads | 16 | from colab.search.utils import get_collaboration_data, get_visible_threads |
17 | from colab.accounts.models import User | 17 | from colab.accounts.models import User |
18 | +from colab.plugins.utils.widget_manager import WidgetManager | ||
18 | 19 | ||
19 | from .forms import (UserCreationForm, ListsForm, UserUpdateForm) | 20 | from .forms import (UserCreationForm, ListsForm, UserUpdateForm) |
20 | from .utils import mailman | 21 | from .utils import mailman |
@@ -42,6 +43,13 @@ class UserProfileUpdateView(UserProfileBaseMixin, UpdateView): | @@ -42,6 +43,13 @@ class UserProfileUpdateView(UserProfileBaseMixin, UpdateView): | ||
42 | 43 | ||
43 | return obj | 44 | return obj |
44 | 45 | ||
46 | + def get_context_data(self, **kwargs): | ||
47 | + context = {} | ||
48 | + context['widgets'] = WidgetManager.get_widgets('profile', self.request) | ||
49 | + context['lala'] = 'lala123' | ||
50 | + context.update(kwargs) | ||
51 | + return super(UserProfileUpdateView, self).get_context_data(**context) | ||
52 | + | ||
45 | 53 | ||
46 | class UserProfileDetailView(UserProfileBaseMixin, DetailView): | 54 | class UserProfileDetailView(UserProfileBaseMixin, DetailView): |
47 | template_name = 'accounts/user_detail.html' | 55 | template_name = 'accounts/user_detail.html' |
@@ -0,0 +1,8 @@ | @@ -0,0 +1,8 @@ | ||
1 | + | ||
2 | + | ||
3 | +default_app_config = 'colab.plugins.gitlab.apps.ProxyGitlabAppConfig' | ||
4 | + | ||
5 | +from colab.plugins.utils.widget_manager import WidgetManager | ||
6 | +from colab.plugins.gitlab.widgets import GitlabProfileWidget | ||
7 | + | ||
8 | +WidgetManager.register_widget('profile', GitlabProfileWidget()) |
@@ -0,0 +1,36 @@ | @@ -0,0 +1,36 @@ | ||
1 | +<rules | ||
2 | + xmlns="http://namespaces.plone.org/diazo" | ||
3 | + xmlns:css="http://namespaces.plone.org/diazo/css" | ||
4 | + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | ||
5 | + | ||
6 | + <xsl:variable name="username" select="str:replace(//a/@href[(contains(., '/gitlab/u/'))], '/gitlab/u/', '')" /> | ||
7 | + <xsl:template match="a/@href[(contains(., '/profile/'))]"> | ||
8 | + <xsl:attribute name="href">/account/<xsl:value-of select="$username"/>/edit?code=<xsl:value-of select="."/>/</xsl:attribute> | ||
9 | + </xsl:template> | ||
10 | + <xsl:template match="form/@action[(contains(., '/gitlab/'))]"> | ||
11 | + <xsl:attribute name="action">/account/<xsl:value-of select="$username"/>/edit?code=<xsl:value-of select="."/>/</xsl:attribute> | ||
12 | + </xsl:template> | ||
13 | + | ||
14 | + <!-- Drop colab stuff --> | ||
15 | + <drop css:theme="nav.navbar-fixed-top" /> | ||
16 | + <drop css:theme="div.footer" /> | ||
17 | + | ||
18 | + <!-- Drop unused tabs on gitlab --> | ||
19 | + <drop content="div[@class='container']/ul/li[1]" /> | ||
20 | + <drop content="div[@class='container']/ul/li[3]" /> | ||
21 | + <drop content="div[@class='container']/ul/li[4]" /> | ||
22 | + <drop content="div[@class='container']/ul/li[7]" /> | ||
23 | + <drop content="fieldset[@class='update-username']" /> | ||
24 | + | ||
25 | + <before theme-children="/html/head" content-children="/html/head" /> | ||
26 | + <before css:theme-children="#main-content" css:content-children="body" /> | ||
27 | + | ||
28 | + <merge attributes="class" css:theme="body" css:content="body" /> | ||
29 | + | ||
30 | + <!-- Add gitlab properties --> | ||
31 | + <merge attributes="data-page" css:theme="body" css:content="body" /> | ||
32 | + <merge attributes="data-project-id" css:theme="body" css:content="body" /> | ||
33 | + | ||
34 | + <drop css:content="#top-panel" /> | ||
35 | + <drop css:content=".navbar-gitlab" /> | ||
36 | +</rules> |
colab/plugins/gitlab/templates/proxy/gitlab_profile.html
0 → 100644
@@ -0,0 +1,50 @@ | @@ -0,0 +1,50 @@ | ||
1 | + | ||
2 | +{% load static from staticfiles %} | ||
3 | + | ||
4 | +{% block head_css %} | ||
5 | +<style> | ||
6 | + /* Reset left and with for .modal-dialog style (like gitlab does), | ||
7 | + the bootstrap.css one makes it small */ | ||
8 | + @media screen and (min-width: 768px) { | ||
9 | + .modal-dialog { | ||
10 | + left: auto; | ||
11 | + width: auto; | ||
12 | + } | ||
13 | + } | ||
14 | + | ||
15 | + div#main-content div.container { | ||
16 | + width: 1110px; | ||
17 | + } | ||
18 | + div#main-content div.flash-container{ | ||
19 | + width: 85%; | ||
20 | + } | ||
21 | + #breadcrumbs { | ||
22 | + border: 0 !important; | ||
23 | + } | ||
24 | + | ||
25 | + #right-top-nav { | ||
26 | + margin-right: 5em !important; | ||
27 | + } | ||
28 | +</style> | ||
29 | +{% endblock %} | ||
30 | + | ||
31 | +{% block head_js %} | ||
32 | +<script>jQuery.noConflict();</script> | ||
33 | +{% endblock %} | ||
34 | +<body> | ||
35 | +</body> | ||
36 | +<div id="main-content"></div> | ||
37 | +<script type="text/javascript"> | ||
38 | + jQuery(function(){ | ||
39 | + // bootstrap.css forces .hide {display:none!important}, and this makes | ||
40 | + // gitlab .hide elements NEVER have a display:block, so | ||
41 | + // instead of editing bootstrap.css, we just removed '.hide' css class and | ||
42 | + // toggled | ||
43 | + jQuery('.hide').removeClass('hide').css('display', 'none'); | ||
44 | + }); | ||
45 | + | ||
46 | + // Extremelly ugly solutions to add Colab's CSRF token to Gitlab forms | ||
47 | + // add CSRF token to HTTP header*** | ||
48 | + jQuery('div#code form').append(jQuery("input[name='csrfmiddlewaretoken']")); | ||
49 | + $('a.delete-key').attr('data-method', 'delete\" type=\"hidden\" /> <input name=\"csrfmiddlewaretoken\" value=\"' + jQuery("input[name='csrfmiddlewaretoken']").val()); | ||
50 | +</script> |
@@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
1 | + | ||
2 | +from django.conf.urls import patterns, url | ||
3 | + | ||
4 | +from .views import GitlabProxyView, GitlabProfileProxyView | ||
5 | + | ||
6 | +urlpatterns = patterns('', | ||
7 | + # Gitlab URLs | ||
8 | + #url(r'(?P<path>profile.*)$', GitlabProfileProxyView.as_view(), name='gitlab'), | ||
9 | + url(r'^(?P<path>.*)$', GitlabProxyView.as_view(), name='gitlab'), | ||
10 | +) |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | + | ||
2 | +from ..utils.views import ColabProxyView | ||
3 | +import os, sys | ||
4 | + | ||
5 | + | ||
6 | +class GitlabProxyView(ColabProxyView): | ||
7 | + app_label = 'gitlab' | ||
8 | + diazo_theme_template = 'proxy/gitlab.html' | ||
9 | + | ||
10 | + | ||
11 | +class GitlabProfileProxyView(ColabProxyView): | ||
12 | + app_label = 'gitlab' | ||
13 | + diazo_theme_template = 'proxy/gitlab_profile.html' | ||
14 | + | ||
15 | + @property | ||
16 | + def diazo_rules(self): | ||
17 | + child_class_file = sys.modules[self.__module__].__file__ | ||
18 | + app_path = os.path.abspath(os.path.dirname(child_class_file)) | ||
19 | + diazo_path = os.path.join(app_path, 'profile/diazo.xml') | ||
20 | + | ||
21 | + self.log.debug("diazo_rules: %s", diazo_path) | ||
22 | + return diazo_path |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +from colab.plugins.gitlab.views import GitlabProxyView, GitlabProfileProxyView | ||
2 | +from colab.plugins.utils.widget_manager import Widget | ||
3 | +from django.utils.safestring import mark_safe | ||
4 | + | ||
5 | + | ||
6 | +class GitlabProfileWidget(GitlabProxyView, Widget): | ||
7 | + identifier = 'code' | ||
8 | + name = 'Gitlab Profile' | ||
9 | + default_url = '/gitlab/profile/account' | ||
10 | + | ||
11 | + def generate_content(self, request): | ||
12 | + requested_url = request.GET.get('code', self.default_url) | ||
13 | + g = GitlabProfileProxyView() | ||
14 | + r = g.dispatch(request, requested_url) | ||
15 | + if r.status_code == 302: | ||
16 | + location = r.get('Location') | ||
17 | + requested_url = location[location.find('/{}/'.format(self.app_label)):] | ||
18 | + request.method = 'GET' | ||
19 | + r = g.dispatch(request, requested_url) | ||
20 | + | ||
21 | + return "<div>" + r.content + "</div>" | ||
0 | \ No newline at end of file | 22 | \ No newline at end of file |
colab/plugins/templatetags/plugins.py
@@ -51,3 +51,23 @@ def plugins_menu(context): | @@ -51,3 +51,23 @@ def plugins_menu(context): | ||
51 | 51 | ||
52 | cache.set(cache_key, menu) | 52 | cache.set(cache_key, menu) |
53 | return menu | 53 | return menu |
54 | + | ||
55 | +import requests | ||
56 | +from django.conf import settings | ||
57 | +from colab.plugins.gitlab.views import GitlabProfileProxyView | ||
58 | +@register.simple_tag(takes_context=True) | ||
59 | +def content_xpto(context): | ||
60 | + request = context['request'] | ||
61 | + requested_url = request.GET.get('code', '/gitlab/profile/account') | ||
62 | + print "requested_url1 = " + requested_url | ||
63 | + | ||
64 | + g = GitlabProfileProxyView() | ||
65 | + r = g.dispatch(request, requested_url) | ||
66 | + if r.status_code == 302: | ||
67 | + location = r.get('Location') | ||
68 | + requested_url = location[location.find('/gitlab/'):] | ||
69 | + request.method = 'GET' | ||
70 | + print "requested_url2 = " + requested_url | ||
71 | + r = g.dispatch(request, requested_url) | ||
72 | + | ||
73 | + return "<div>" + r.content + "</div>" |
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | + | ||
2 | +class Widget: | ||
3 | + identifier = None | ||
4 | + name = None | ||
5 | + default_url = None | ||
6 | + content = None | ||
7 | + | ||
8 | + def get_body(self): | ||
9 | + # avoiding regex in favor of performance | ||
10 | + start = content.find('<body>') | ||
11 | + end = content.find('</body>') | ||
12 | + head = content[start + len('<body>'):end] | ||
13 | + return head | ||
14 | + | ||
15 | + def get_header(self): | ||
16 | + # avoiding regex in favor of performance | ||
17 | + start = content.find('<head>') | ||
18 | + end = content.find('</head>') | ||
19 | + head = content[start + len('<head>'):end] | ||
20 | + return head | ||
21 | + | ||
22 | + def generate_content(self, request=None): | ||
23 | + self.content = '' | ||
24 | + | ||
25 | + | ||
26 | +class WidgetManager(object): | ||
27 | + widget_categories = {} | ||
28 | + | ||
29 | + @staticmethod | ||
30 | + def register_widget(category, widget): | ||
31 | + if not WidgetManager.widget_categories.has_key(category): | ||
32 | + WidgetManager.widget_categories[category] = [] | ||
33 | + | ||
34 | + WidgetManager.widget_categories[category].append(widget) | ||
35 | + | ||
36 | + @staticmethod | ||
37 | + def get_widgets(category, request=None): | ||
38 | + if not WidgetManager.widget_categories.has_key(category): | ||
39 | + return [] | ||
40 | + | ||
41 | + widgets = WidgetManager.widget_categories[category] | ||
42 | + for widget in widgets: | ||
43 | + widget.generate_content(request) | ||
44 | + return widgets |
colab/urls.py
@@ -3,7 +3,7 @@ from django.conf import settings | @@ -3,7 +3,7 @@ from django.conf import settings | ||
3 | from django.views.generic import TemplateView | 3 | from django.views.generic import TemplateView |
4 | from django.contrib import admin | 4 | from django.contrib import admin |
5 | from django.views.generic import RedirectView | 5 | from django.views.generic import RedirectView |
6 | - | 6 | +from accounts.views import UserProfileUpdateView |
7 | 7 | ||
8 | admin.autodiscover() | 8 | admin.autodiscover() |
9 | 9 |
No preview for this file type