Commit 3a9f4931 authored by Sofia Papagiannaki's avatar Sofia Papagiannaki

integration with aquarium: Progress III & merge master

Refs: #1824
parent 660c7a4f
v0.3.2
======
- improved styles of sign up button
- do not send admin notification email if ASTAKOS_DEFAULT_ADMIN_EMAIL is not
set
- updated cloudbar styles
v0.3.1
======
......
......@@ -62,10 +62,17 @@ ASTAKOS_MODERATION_ENABLED True
ASTAKOS_BASEURL \http://pithos.dev.grnet.gr Astakos baseurl
ASTAKOS_SITENAME GRNET Cloud Service name that appears in emails
ASTAKOS_CLOUD_SERVICES ({'icon': 'home-icon.png', 'id': 'cloud', 'name': 'grnet cloud', 'url': '/'}, Cloud services appear in the horizontal bar
{'id': 'okeanos', 'name': '~okeanos', 'url': '/okeanos.html'},
{'id': 'okeanos', 'name': 'cyclades', 'url': '/okeanos.html'},
{'id': 'pithos', 'name': 'pithos+', 'url': '/ui/'})
ASTAKOS_RECAPTCHA_PUBLIC_KEY Recaptcha public key obtained after registration here: http://recaptcha.net
ASTAKOS_RECAPTCHA_PRIVATE_KEY Recaptcha private key obtained after registration here: http://recaptcha.net
ASTAKOS_RECAPTCHA_OPTIONS {'theme': 'white'} Options for customizing reCAPTCHA look and feel
(see: http://code.google.com/intl/el-GR/apis/recaptcha/docs/customization.html)
ASTAKOS_LOGOUT_NEXT Where the user should be redirected after logout
(if not set and no next parameter is defined it renders login page with message)
ASTAKOS_BILLING_FIELDS ['id', 'is_active', 'provider', 'third_party_identifier'] AstakosUser fields to propagate in the billing system
ASTAKOS_QUEUE_CONNECTION The queue connection ex. 'rabbitmq://guest:guest@localhost:5672/astakos.userEvent.#'
(if it is not set, it does not send messages)
============================== ============================================================================= ===========================================================================================
Administrator functions
......
......@@ -31,6 +31,8 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
import logging
from traceback import format_exc
from time import time, mktime
from urllib import quote
......@@ -45,6 +47,8 @@ from astakos.im.faults import BadRequest, Unauthorized, InternalServerError
from astakos.im.models import AstakosUser
from astakos.im.settings import CLOUD_SERVICES, INVITATIONS_ENABLED
logger = logging.getLogger(__name__)
def render_fault(request, fault):
if isinstance(fault, InternalServerError) and settings.DEBUG:
fault.details = format_exc(fault)
......@@ -94,6 +98,7 @@ def authenticate(request):
response['Content-Length'] = len(response.content)
return response
except BaseException, e:
logger.exception(e)
fault = InternalServerError('Unexpected error')
return render_fault(request, fault)
......@@ -119,23 +124,23 @@ def get_menu(request):
index_url = absolute(reverse('astakos.im.views.index'))
if urlparse(location).query.rfind('next=') == -1:
index_url = '%s?next=%s' % (index_url, quote(location))
l = [{ 'url': index_url, 'name': "login..."}]
l = [{ 'url': index_url, 'name': "Sign in"}]
if request.user.is_authenticated():
l = []
l.append({ 'url': absolute(reverse('astakos.im.views.edit_profile')),
'name': request.user.email})
l.append({ 'url': absolute(reverse('astakos.im.views.edit_profile')),
'name': "view your profile..." })
'name': "View your profile" })
if request.user.password:
l.append({ 'url': absolute(reverse('password_change')),
'name': "change your password..." })
'name': "Change your password" })
if INVITATIONS_ENABLED:
l.append({ 'url': absolute(reverse('astakos.im.views.invite')),
'name': "invite some friends..." })
'name': "Invite some friends" })
l.append({ 'url': absolute(reverse('astakos.im.views.send_feedback')),
'name': "feedback..." })
'name': "Send feedback" })
l.append({ 'url': absolute(reverse('astakos.im.views.logout')),
'name': "logout..."})
'name': "Sign out"})
callback = request.GET.get('callback', None)
data = json.dumps(tuple(l))
......
......@@ -164,7 +164,10 @@ class InvitationsBackend(object):
message = _('Registration completed. You can now login.')
else:
_send_notification(user, admin_email_template_name)
message = _('Registration completed. You will receive an email upon your account\'s activation.')
message = _('Your request for an account was successfully sent \
and pending approval from our administrators. You \
will be notified by email the next days. \
Thanks for being patient, the GRNET team')
status = messages.SUCCESS
except Invitation.DoesNotExist, e:
status = messages.ERROR
......@@ -233,7 +236,10 @@ class SimpleBackend(object):
if MODERATION_ENABLED:
try:
_send_notification(user, admin_email_template_name)
message = _('Registration completed. You will receive an email upon your account\'s activation.')
message = _('Your request for an account was successfully sent \
and pending approval from our administrators. You \
will be notified by email the next days. \
Thanks for being patient, the GRNET team')
except (SMTPException, socket.error) as e:
status = messages.ERROR
name = 'strerror'
......
......@@ -41,7 +41,7 @@ from base64 import b64encode
from django.db import models
from django.contrib.auth.models import User, UserManager
from astakos.im.settings import DEFAULT_USER_LEVEL, INVITATIONS_PER_LEVEL, AUTH_TOKEN_DURATION, BILLING_FIELDS, QUEUE_EXCHANGE
from astakos.im.settings import DEFAULT_USER_LEVEL, INVITATIONS_PER_LEVEL, AUTH_TOKEN_DURATION, BILLING_FIELDS, QUEUE_CONNECTION
from synnefo.lib.queue import exchange_connect, exchange_send, exchange_close, Receipt
QUEUE_CLIENT_ID = 3 # Astakos.
......@@ -162,12 +162,12 @@ def report_user_event(user):
return True
return False
if QUEUE_EXCHANGE and should_send(user):
if QUEUE_CONNECTION and should_send(user):
l = [[elem, str(user.__getattribute__(elem))] for elem in BILLING_FIELDS]
details = dict(l)
details['eventType'] = 'create' if not user.id else 'modify'
body = Receipt(QUEUE_CLIENT_ID, user.email, '', 0, details).format()
conn = exchange_connect(QUEUE_EXCHANGE)
routing_key = QUEUE_EXCHANGE.replace('#', body['id'])
conn = exchange_connect(QUEUE_CONNECTION)
routing_key = QUEUE_CONNECTION.replace('#', body['id'])
exchange_send(conn, routing_key, body)
exchange_close(conn)
\ No newline at end of file
......@@ -50,7 +50,7 @@ SITENAME = getattr(settings, 'ASTAKOS_SITENAME', 'GRNET Cloud')
# Set cloud services appear in the horizontal bar
CLOUD_SERVICES = getattr(settings, 'ASTAKOS_CLOUD_SERVICES', (
{ 'url':'/', 'name':'grnet cloud', 'id':'cloud', 'icon':'home-icon.png' },
{ 'url':'/okeanos.html', 'name':'~okeanos', 'id':'okeanos' },
{ 'url':'/okeanos.html', 'name':'cyclades', 'id':'okeanos' },
{ 'url':'/ui/', 'name':'pithos+', 'id':'pithos' }))
# Set recaptcha keys
......@@ -62,4 +62,7 @@ RECAPTCHA_OPTIONS = getattr(settings, 'ASTAKOS_RECAPTCHA_OPTIONS', {'theme': 'wh
BILLING_FIELDS = getattr(settings, 'ASTAKOS_BILLING_FIELDS', ['id', 'is_active', 'provider', 'third_party_identifier'])
# Queue for billing.
QUEUE_EXCHANGE = getattr(settings, 'ASTAKOS_QUEUE_EXCHANGE', None) # Example: 'rabbitmq://guest:guest@localhost:5672/astakos.userEvent.#'
\ No newline at end of file
QUEUE_CONNECTION = getattr(settings, 'ASTAKOS_QUEUE_CONNECTION', None) # Example: 'rabbitmq://guest:guest@localhost:5672/astakos.userEvent.#'
# Set where the user should be redirected after logout
LOGOUT_NEXT = getattr(settings, 'ASTAKOS_LOGOUT_NEXT', '')
\ No newline at end of file
......@@ -5,7 +5,7 @@
* Snippets of reusable CSS to develop faster and keep code readable
* ----------------------------------------------------------------- */
.servicesbar {
font-family: arial, sans-serif;
font-family: arial, sans-serif !important;
font-size: 13px !important;
line-height: 13px;
letter-spacing: 0px;
......@@ -35,7 +35,8 @@
}
.servicesbar a {
border: none !important;
font-size: inherit !important;
font-family: arial, sans-serif !important;
font-size: 13px !important;
color: #e6e6e6;
text-decoration: none;
display: block;
......@@ -48,6 +49,7 @@
}
.servicesbar a.active {
font-weight: bold;
font-size: 13px !important;
background-color: #333;
}
.servicesbar a img {
......@@ -66,6 +68,18 @@
.servicesbar .services:after {
clear: both;
}
.servicesbar .services a {
font-size: 13px !important;
font-weight: bold;
color: #ccc;
}
.servicesbar .services a.active {
font-size: 13px !important;
color: #ffffff !important;
}
.servicesbar .services a:hover {
background-color: #444;
}
.servicesbar .profile {
margin-top: -35px;
zoom: 1;
......@@ -86,6 +100,10 @@
.servicesbar .profile:after {
clear: both;
}
.servicesbar .profile .user > a {
font-weight: bold !important;
font-size: 12px !important;
}
.servicesbar .profile a {
float: none;
}
......
......@@ -10,7 +10,7 @@
// mini reset
ol, ul { list-style:none; margin:0; padding:0;}
li {margin:0; padding:0;}
font-family: arial, sans-serif;
font-family: arial, sans-serif !important;
font-size: 13px !important;
line-height: 13px;
letter-spacing: 0px;
......@@ -23,7 +23,8 @@
a {
border: none !important;
font-size: inherit !important;
font-family: arial, sans-serif !important;
font-size: 13px !important;
color: @toolbarColor;
text-decoration: none;
display: block;
......@@ -35,6 +36,7 @@
}
&.active {
font-weight: bold;
font-size: 13px !important;
background-color: #333;
}
......@@ -47,6 +49,20 @@
.services {
.clearfix();
a {
font-size: 13px !important;
font-weight: bold;
color: #ccc;
&.active {
font-size: 13px !important;
color: @white !important;
}
&:hover {
background-color: #444;
}
}
}
position: relative;
......@@ -57,6 +73,13 @@
text-align: right;
min-width: 200px;
width: 200px;
.user {
&> a {
font-weight: bold !important;
font-size: 12px !important;
}
}
a {
float: none;
}
......
......@@ -189,12 +189,21 @@ textarea {
clear: both;
}
.button {
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
background-color: #3582ac;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.15s linear;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.15s linear;
color: #ffffff;
border: none;
padding: 0.8em 22px;
......@@ -203,6 +212,62 @@ textarea {
.button:hover {
background-color: #f89a1c;
}
.button a {
color: #ffffff !important;
text-decoration: none !important;
border: none !important;
}
a.button {
color: #ffffff !important;
text-decoration: none !important;
border: none !important;
}
.makeRow {
zoom: 1;
margin-left: -22px;
}
.makeRow:before, .makeRow:after {
display: table;
content: "";
zoom: 1;
}
.makeRow:after {
clear: both;
}
.button {
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
background-color: #3582ac;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.15s linear;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.15s linear;
color: #ffffff;
border: none;
padding: 0.8em 22px;
font-size: 1em;
}
.button:hover {
background-color: #f89a1c;
}
.button a {
color: #ffffff !important;
text-decoration: none !important;
border: none !important;
}
a.button {
color: #ffffff !important;
text-decoration: none !important;
border: none !important;
}
/*addon to style django forms rendered with as_p filter*/
/*
* Tables.less
......@@ -411,6 +476,11 @@ body {
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
}
.topbar {
background-color: #cfcdc7;
......@@ -586,6 +656,8 @@ ul.inline li {
color: #f89a1c;
}
.page {
zoom: 1;
margin-left: -22px;
zoom: 1;
margin-left: -22px;
margin-top: 42px;
......@@ -599,6 +671,14 @@ ul.inline li {
.page:after {
clear: both;
}
.page:before, .page:after {
display: table;
content: "";
zoom: 1;
}
.page:after {
clear: both;
}
.page .page-inner {
position: relative;
}
......@@ -615,6 +695,8 @@ ul.inline li {
width: 470px;
}
.maincol.full {
zoom: 1;
margin-left: -22px;
zoom: 1;
margin-left: -22px;
margin-left: 0;
......@@ -631,6 +713,14 @@ ul.inline li {
.maincol.full:after {
clear: both;
}
.maincol.full:before, .maincol.full:after {
display: table;
content: "";
zoom: 1;
}
.maincol.full:after {
clear: both;
}
.appbar {
height: 30px;
background-color: #3582ac;
......@@ -677,6 +767,11 @@ input, textarea, .form-widget {
margin-top: 9px;
}
#forms .input, #forms input {
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
......@@ -799,6 +894,11 @@ form textarea,
form input.text,
form input[type="text"],
form input[type="password"] {
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
......@@ -819,12 +919,40 @@ form input[type="password"]:focus {
z-index: 100;
}
form input.submit, form input[type="submit"] {
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
background-color: #3582ac;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.15s linear;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.15s linear;
color: #ffffff;
border: none;
padding: 0.8em 22px;
font-size: 1em;
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
font-family: 'Antic', sans-serif;
font-size: 14px;
font-weight: normal;
line-height: 22px;
letter-spacing: 1px;
background-color: #3582ac;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.15s linear;
-webkit-transition: background-color 0.15s linear;
transition: background-color 0.15s linear;
color: #ffffff;
border: none;
padding: 0.8em 22px;
......@@ -833,6 +961,19 @@ form input.submit, form input[type="submit"] {
form input.submit:hover, form input[type="submit"]:hover {
background-color: #f89a1c;
}
form input.submit a, form input[type="submit"] a {
color: #ffffff !important;
text-decoration: none !important;
border: none !important;
}
form input.submit:hover, form input[type="submit"]:hover {
background-color: #f89a1c;
}
form input.submit a, form input[type="submit"] a {
color: #ffffff !important;
text-decoration: none !important;
border: none !important;
}
form .with-errors input, form .with-errors textarea, form .with-errors select {
color: #9d261d;
}
......@@ -900,6 +1041,16 @@ table tr.consumed td.consumed {
.row {
zoom: 1;
margin-left: -22px;
zoom: 1;
margin-left: -22px;
}
.row:before, .row:after {
display: table;
content: "";
zoom: 1;
}
.row:after {
clear: both;
}
.row:before, .row:after {
display: table;
......@@ -913,11 +1064,15 @@ table tr.consumed td.consumed {
color: #808080 !important;
-webkit-transition: color 0.15s linear;
transition: color 0.15s linear;
-webkit-transition: color 0.15s linear;
transition: color 0.15s linear;
}
.footer a {
color: #b3b3b3;
-webkit-transition: color 0.15s linear;
transition: color 0.15s linear;
-webkit-transition: color 0.15s linear;
transition: color 0.15s linear;
text-decoration: none;
}
.footer a:hover {
......
@import "../less/bootstrap.less";
@import "../less/xtra.less";
@import "../less/django_forms.less";
@import "../less/tables.less";
......
......@@ -16,6 +16,7 @@
.button {
#font.main();
background-color: @buttonBg;
.transit(background-color);
color: @buttonColor;
border: none;
padding: 0.8em @gridGutterWidth;
......@@ -24,6 +25,18 @@
&:hover {
background-color: @linkColor;
}
a {
color: @white !important;
text-decoration: none !important;
border: none !important;
}
}
a.button {
color: @white !important;
text-decoration: none !important;
border: none !important;
}
......
......@@ -37,9 +37,13 @@ Login
</div>
{% endfor %}
</div>
<div class="section">
<a href="{% url astakos.im.views.signup %}" class="action">SIGN UP</a>
{% block body.signup %}
<div class="section signup">
<br /><br />
<h2>NEW TO OKEANOS ?</h2>
<a class="button" href="{% url astakos.im.views.signup %}">CREATE ACCOUNT</a>
</div>
</div>
{% endblock %}
{% endblock %}
......@@ -33,7 +33,7 @@
from django.conf.urls.defaults import patterns, include, url
from astakos.im.forms import ExtendedPasswordResetForm
from astakos.im.forms import ExtendedPasswordResetForm, LoginForm
from astakos.im.settings import IM_MODULES, INVITATIONS_ENABLED
urlpatterns = patterns('astakos.im.views',
......@@ -41,8 +41,8 @@ urlpatterns = patterns('astakos.im.views',
url(r'^login/?$', 'index'),
url(r'^profile/?$', 'edit_profile'),
url(r'^feedback/?$', 'send_feedback'),
url(r'^signup/?$', 'signup'),
url(r'^logout/?$', 'logout'),
url(r'^signup/?$', 'signup', {'on_success':'im/login.html', 'extra_context':{'form':LoginForm()}}),
url(r'^logout/?$', 'logout', {'template':'im/login.html', 'extra_context':{'form':LoginForm()}}),
url(r'^activate/?$', 'activate')
)
......
......@@ -55,7 +55,7 @@ from astakos.im.models import AstakosUser, Invitation
from astakos.im.backends import get_backend
from astakos.im.util import get_context, prepare_response, set_cookie
from astakos.im.forms import *
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, BASEURL
from astakos.im.settings import DEFAULT_CONTACT_EMAIL, DEFAULT_FROM_EMAIL, COOKIE_NAME, COOKIE_DOMAIN, IM_MODULES, SITENAME, BASEURL, LOGOUT_NEXT
from astakos.im.functions import invite as invite_func
logger =