@@ -22,7 +22,10 @@ local = Local() | |||
class _dict(dict): | |||
"""dict like object that exposes keys as attributes""" | |||
def __getattr__(self, key): | |||
return self.get(key) | |||
ret = self.get(key) | |||
if not ret and key.startswith("__"): | |||
raise AttributeError() | |||
return ret | |||
def __setattr__(self, key, value): | |||
self[key] = value | |||
def __getstate__(self): | |||
@@ -69,7 +69,6 @@ def get_bootinfo(): | |||
from webnotes.model.utils import compress | |||
bootinfo['docs'] = compress(bootinfo['docs']) | |||
# deal with __slots__ in lang | |||
if bootinfo.lang: | |||
bootinfo.lang = unicode(bootinfo.lang) | |||
@@ -240,7 +240,6 @@ def use(): | |||
@cmd | |||
def install(db_name, root_login="root", root_password=None, source_sql=None, | |||
admin_password = 'admin', verbose=True, force=False, site_config=None, reinstall=False): | |||
print db_name, source_sql | |||
from webnotes.installer import install_db, install_app, make_site_dirs | |||
install_db(root_login=root_login, root_password=root_password, db_name=db_name, source_sql=source_sql, | |||
admin_password = admin_password, verbose=verbose, force=force, site_config=site_config, reinstall=reinstall) | |||
@@ -2,7 +2,7 @@ | |||
{ | |||
"creation": "2012-08-02 15:17:28", | |||
"docstatus": 0, | |||
"modified": "2013-12-20 19:23:58", | |||
"modified": "2014-02-12 21:11:05", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
@@ -55,7 +55,7 @@ | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "message", | |||
"fieldtype": "Text", | |||
"fieldtype": "Long Text", | |||
"label": "Message" | |||
}, | |||
{ | |||
@@ -132,7 +132,7 @@ wn.desktop.show_all_modules = function() { | |||
var module = wn.modules[m]; | |||
if(module.link && desktop_items.indexOf(m)!==-1) { | |||
module.app_icon = wn.ui.app_icon.get_html(m, true); | |||
$(repl('<div class="list-group-item" data-label="%(label)s">\ | |||
$(repl('<div class="list-group-item" data-label="%(name)s">\ | |||
<div class="row">\ | |||
<div class="col-xs-2"><a href="#%(link)s">%(app_icon)s</a></div>\ | |||
<div class="col-xs-10" style="padding-top: 14px;">\ | |||
@@ -178,6 +178,8 @@ class Document: | |||
elif self.fields.has_key(name): | |||
return self.fields[name] | |||
else: | |||
if name.startswith("__"): | |||
raise AttributeError() | |||
return '' | |||
def get(self, name, value=None): | |||
@@ -7,8 +7,8 @@ | |||
<meta name="generator" content="wnframework"> | |||
<script type="text/javascript" src="/assets/webnotes/js/lib/jquery/jquery.min.js"></script> | |||
<link rel="shortcut icon" href="{{ favicon }}" type="image/x-icon"> | |||
<link rel="icon" href="{{ favicon }}" type="image/x-icon"> | |||
<link rel="shortcut icon" href="{{ favicon or "" }}" type="image/x-icon"> | |||
<link rel="icon" href="{{ favicon or "" }}" type="image/x-icon"> | |||
{% block head -%} | |||
{%- if meta_description is defined -%} | |||
@@ -49,12 +49,17 @@ | |||
<header class="page-header"> | |||
<div class="container" data-html-block="header"> | |||
{%- if header is defined -%}{{ header }}{%- endif -%} | |||
{%- if header is defined -%}{{ header }}{% elif title is defined %}<h2>{{ title }}</h2>{%- endif -%} | |||
</div> | |||
</header> | |||
<header class="page-breadcrumbs"> | |||
<div class="container" data-html-block="breadcrumbs"> | |||
{%- if breadcrumbs is defined -%}{{ breadcrumbs }}{%- endif -%} | |||
<div class="container"> | |||
<div class="row"> | |||
<div class="col-xs-10 page-breadcrumbs" data-html-block="breadcrumbs"> | |||
{%- if breadcrumbs is defined -%}{{ breadcrumbs }}{%- endif -%} | |||
</div> | |||
<div class="col-xs-2 text-right"><a class="visible-xs toggle-sidebar no-decoration"> | |||
<i class="icon-chevron-down"></i> | |||
</a></div> | |||
</div> | |||
</div> | |||
</header> | |||
<div class="container page-container" id="page-{{ name or page_name }}"> | |||
@@ -68,9 +73,6 @@ | |||
{%- endblock -%} | |||
</div> | |||
<div class="col-sm-9 col-sm-pull-3 page-content" data-html-block="content"> | |||
<div class="text-right"><a class="visible-xs toggle-sidebar no-decoration"> | |||
<i class="icon-chevron-down"></i> | |||
</a></div> | |||
{%- block content -%}{{ content }}{%- endblock -%} | |||
</div> | |||
</div> | |||
@@ -78,6 +78,19 @@ body { | |||
padding:10px 0; | |||
} | |||
.left-padding { | |||
padding-left: 10px; | |||
} | |||
.breadcrumb { | |||
list-style: none; | |||
} | |||
.breadcrumb > li { | |||
display: inline-block; | |||
margin-left: 0px; | |||
margin-right: 5px; | |||
} | |||
/* ------------------------------------- | |||
BODY | |||
@@ -183,6 +196,19 @@ table.footer-wrap a{ | |||
width: 100%; | |||
} | |||
a.no-decoration { | |||
text-decoration: none; | |||
color: inherit; | |||
} | |||
small, .small { | |||
font-size: 85%; | |||
} | |||
.text-muted { | |||
color: #999999; | |||
} | |||
</style> | |||
</head> | |||
@@ -240,7 +266,7 @@ table.footer-wrap a{ | |||
</div> | |||
<div class="print-html">{{ print_html }}</div> | |||
<div class="print-html">{{ print_html or "" }}</div> | |||
</body> | |||
</html> |
@@ -10,8 +10,6 @@ | |||
{% endfor %} | |||
</ul> | |||
</div> | |||
<div id="website-login" class="col-xs-3 text-right"> | |||
<a href="login">Login</a></div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-8"> | |||
@@ -5,13 +5,13 @@ | |||
data-name="{{ post.name }}" | |||
data-group="{{ post.website_group }}" | |||
itemscope itemtype="http://schema.org/Article"> | |||
<a class="pull-left media-link" href="{{ post_url }}"> | |||
<a class="pull-left media-link" {% if view.name!="post" %} href="{{ post_url }}" {% endif %}> | |||
<img class="media-object post-avatar" src="{{ post.user_image }}"> | |||
</a> | |||
<div class="media-body"> | |||
{%- if not post.parent_post -%} | |||
<h4 class="media-heading" itemprop="headline"> | |||
{%- if view != "post" -%} | |||
{%- if view.name != "post" -%} | |||
<a class="no-decoration" | |||
href="{{ post_url }}">{{ post.title }}</a> | |||
{%- else -%} | |||
@@ -66,7 +66,7 @@ | |||
</ul> | |||
</li> | |||
</ul> | |||
<ul class="btn-login-area nav navbar-nav navbar-right"> | |||
<ul class="btn-login-area website-login nav navbar-nav navbar-right"> | |||
<li><a href="/login">Sign Up / Login</a></li> | |||
</ul> | |||
</div> | |||
@@ -1,7 +1,7 @@ | |||
{% if children -%} | |||
{%- for child in children -%} | |||
<div class="sidebar-item"> | |||
<a href="/{{ child.name|lower }}" class="no-decoration"> | |||
<a href="{{ child.name }}" class="no-decoration {% if child.name == pathname %}active{% endif %}"> | |||
{{ child.page_title }} | |||
{% if not child.public_read %} | |||
(<i class="icon-fixed-width icon-lock"></i>) | |||
@@ -903,9 +903,16 @@ def scrub_urls(html): | |||
def expand_relative_urls(html): | |||
# expand relative urls | |||
url = get_url() | |||
if not url.endswith("/"): url += "/" | |||
return re.sub('(href|src){1}([\s]*=[\s]*[\'"]?)((?!http)[^\'" >]+)([\'"]?)', | |||
'\g<1>\g<2>{}\g<3>\g<4>'.format(url), html) | |||
if url.endswith("/"): url = url[:-1] | |||
def _expand_relative_urls(match): | |||
to_expand = list(match.groups()) | |||
if not to_expand[2].startswith("/"): | |||
to_expand[2] = "/" + to_expand[2] | |||
to_expand.insert(2, url) | |||
return "".join(to_expand) | |||
return re.sub('(href|src){1}([\s]*=[\s]*[\'"]?)((?!http)[^\'" >]+)([\'"]?)', _expand_relative_urls, html) | |||
def quote_urls(html): | |||
def _quote_url(match): | |||
@@ -47,7 +47,7 @@ def send(recipients=None, sender=None, doctype='Profile', email_field='email', | |||
"type": doctype, | |||
"email_field": email_field | |||
})) | |||
updated = updated.replace("<!--unsubscribe link here-->", unsubscribe_link) | |||
return updated | |||
@@ -57,11 +57,6 @@ def send(recipients=None, sender=None, doctype='Profile', email_field='email', | |||
sender = webnotes.conn.get_value('Email Settings', None, 'auto_email_id') | |||
check_bulk_limit(len(recipients)) | |||
try: | |||
text_content = html2text(message) | |||
except HTMLParser.HTMLParseError: | |||
text_content = "[See html attachment]" | |||
formatted = get_formatted_html(subject, message) | |||
for r in filter(None, list(set(recipients))): | |||
@@ -72,8 +67,13 @@ def send(recipients=None, sender=None, doctype='Profile', email_field='email', | |||
if not is_unsubscribed(doc): | |||
# add to queue | |||
add(r, sender, subject, update_message(formatted, doc, add_unsubscribe_link), | |||
text_content, ref_doctype, ref_docname) | |||
updated = update_message(formatted, doc, add_unsubscribe_link) | |||
try: | |||
text_content = html2text(updated) | |||
except HTMLParser.HTMLParseError: | |||
text_content = "[See html attachment]" | |||
add(r, sender, subject, updated, text_content, ref_doctype, ref_docname) | |||
def add(email, sender, subject, formatted, text_content=None, | |||
ref_doctype=None, ref_docname=None): | |||
@@ -83,7 +83,7 @@ def add(email, sender, subject, formatted, text_content=None, | |||
e.recipient = email | |||
try: | |||
e.message = get_email(email, sender=e.sender, formatted=formatted, subject=subject, | |||
text_content = text_content).as_string() | |||
text_content=text_content).as_string() | |||
except webnotes.ValidationError: | |||
# bad email id - don't add to queue | |||
return | |||
@@ -113,7 +113,7 @@ def unsubscribe(): | |||
def flush(from_test=False): | |||
"""flush email queue, every time: called from scheduler""" | |||
smptserver = SMTPServer() | |||
smtpserver = SMTPServer() | |||
auto_commit = not from_test | |||
@@ -133,7 +133,7 @@ def flush(from_test=False): | |||
(email["name"],), auto_commit=auto_commit) | |||
try: | |||
if not from_test: | |||
smptserver.sess.sendmail(email["sender"], email["recipient"], email["message"]) | |||
smtpserver.sess.sendmail(email["sender"], email["recipient"], email["message"]) | |||
webnotes.conn.sql("""update `tabBulk Email` set status='Sent' where name=%s""", | |||
(email["name"],), auto_commit=auto_commit) | |||
@@ -21,7 +21,7 @@ def send(email, as_bulk=False): | |||
if not email.reply_to: | |||
email.reply_to = email.sender | |||
email.sender = smtpserver.login | |||
smtpserver.sess.sendmail(email.sender, email.recipients + (email.cc or []), | |||
email.as_string()) | |||
@@ -215,7 +215,7 @@ fieldset { | |||
.page-header { | |||
margin: 0px; | |||
padding: 5px 0px; | |||
padding: 15px 0px; | |||
} | |||
.page-container { | |||
@@ -233,10 +233,14 @@ fieldset { | |||
margin-bottom: 5px; | |||
} | |||
.page-content { | |||
padding-top: 7px; | |||
} | |||
.sidebar-item { | |||
margin: 15px auto; | |||
color: #999; | |||
font-size: 90%; | |||
font-size: 85%; | |||
} | |||
.sidebar-item a:hover { | |||
@@ -346,10 +350,6 @@ textarea { | |||
margin: 30px; | |||
} | |||
.img-responsive { | |||
border-radius: 4px; | |||
} | |||
.user-profile { | |||
min-height: 50px; | |||
min-width: 70px; | |||
@@ -388,20 +388,23 @@ a.no-decoration { | |||
color: inherit; | |||
} | |||
.page-breadcrumbs { | |||
border-bottom: 1px solid #eee; | |||
a.active { | |||
pointer-events: none; | |||
cursor: default; | |||
color: initial; | |||
} | |||
.page-breadcrumbs .breadcrumb { | |||
margin-bottom: 0px; | |||
padding: 0px; | |||
margin-bottom: 2px; | |||
background-color: transparent; | |||
border-radius: 0px; | |||
padding: 8px 0px; | |||
font-size: 85%; | |||
} | |||
@media (min-width: 768px) { | |||
.page-sidebar { | |||
padding-left: 5em; | |||
padding-left: 3em; | |||
} | |||
} | |||
@@ -48,7 +48,7 @@ def _sync_statics(): | |||
def sync_file(fname, fpath, statics_path, priority=0): | |||
url = os.path.relpath(fpath, statics_path).rsplit(".", 1)[0] | |||
if fname.rsplit(".", 1)[0]=="index": | |||
if fname.rsplit(".", 1)[0]=="index" and os.path.dirname(fpath) != statics_path: | |||
url = os.path.dirname(url) | |||
parent_website_sitemap = os.path.dirname(url) | |||
@@ -100,20 +100,21 @@ def _sync_statics(): | |||
with open(os.path.join(basepath, "index.txt"), "r") as indexfile: | |||
index = indexfile.read().splitlines() | |||
for fname in files: | |||
page_name = fname.rsplit(".", 1)[0] | |||
if page_name=="index" and fname!="index.txt": | |||
sync_file(fname, os.path.join(basepath, fname), statics_path) | |||
has_index = True | |||
break | |||
if basepath!=statics_path: | |||
for fname in files: | |||
page_name = fname.rsplit(".", 1)[0] | |||
if page_name=="index" and fname!="index.txt": | |||
sync_file(fname, os.path.join(basepath, fname), statics_path) | |||
has_index = True | |||
break | |||
if not has_index: | |||
continue | |||
if not has_index: | |||
continue | |||
# other files | |||
for fname in files: | |||
page_name = fname.rsplit(".", 1)[0] | |||
if page_name!="index": | |||
if not (page_name=="index" and basepath!=statics_path): | |||
sync_file(fname, os.path.join(basepath, fname), statics_path, | |||
index.index(page_name) if page_name in index else 0) | |||
@@ -244,23 +244,19 @@ $.extend(wn, { | |||
}, | |||
load_via_ajax: function(href) { | |||
console.log("calling ajax"); | |||
// console.log("calling ajax"); | |||
window.previous_href = href; | |||
history.pushState(null, null, href); | |||
$.ajax({ url: href, cache: false }).done(function(data) { | |||
history.replaceState(data, data.title, href); | |||
$("html, body").animate({ scrollTop: 0 }, "slow"); | |||
wn.render_json(data); | |||
}) | |||
}, | |||
render_json: function(data) { | |||
if(data.reload) { | |||
window.location = location.href; | |||
// } else if(data.html) { | |||
// var newDoc = document.open("text/html", "replace"); | |||
// newDoc.write(data.html); | |||
// newDoc.close(); | |||
} else { | |||
$('[data-html-block]').each(function(i, section) { | |||
var $section = $(section); | |||
@@ -422,9 +418,10 @@ $(document).ready(function() { | |||
}); | |||
$(document).on("page_change", function() { | |||
$(".page-header").toggleClass("hidden", !!!$(".page-header").text().trim()); | |||
$(".page-header").toggleClass("hidden", !!!$("[data-html-block='header']").text().trim()); | |||
$(".page-footer").toggleClass("hidden", !!!$(".page-footer").text().trim()); | |||
//$(".page-breadcrumbs").toggleClass("hidden", !!!$(".page-breadcrumbs").text().trim()); | |||
$("[data-html-block='breadcrumbs'] .breadcrumb").toggleClass("hidden", | |||
$("[data-html-block='breadcrumbs']").text().trim()==$("[data-html-block='header']").text().trim()); | |||
// add prive pages to sidebar | |||
if(website.private_pages && $(".page-sidebar").length) { | |||
@@ -86,11 +86,13 @@ def build_page(path): | |||
def get_context(path): | |||
context = None | |||
cache_key = "page_context:{}".format(path) | |||
from pickle import dump | |||
from StringIO import StringIO | |||
# try from memcache | |||
if can_cache(): | |||
context = webnotes.cache().get_value(cache_key) | |||
if not context: | |||
context = get_sitemap_options(path) | |||
@@ -99,8 +101,7 @@ def get_context(path): | |||
context = build_context(context) | |||
if can_cache(context.no_cache): | |||
del context["access"] | |||
if can_cache(context.no_cache): | |||
webnotes.cache().set_value(cache_key, context) | |||
else: | |||
@@ -147,7 +148,14 @@ def build_sitemap_options(path): | |||
sitemap_options.children = webnotes.conn.sql("""select * from `tabWebsite Sitemap` | |||
where parent_website_sitemap=%s | |||
and public_read=1 order by idx asc""", (sitemap_options.name,), as_dict=True) | |||
and public_read=1 order by -idx desc, page_title asc""", (sitemap_options.pathname,), as_dict=True) | |||
# leaf node, show siblings | |||
if not sitemap_options.children: | |||
sitemap_options.children = webnotes.conn.sql("""select * from `tabWebsite Sitemap` | |||
where ifnull(parent_website_sitemap, '')=%s | |||
and public_read=1 order by -idx desc, page_title asc""", | |||
sitemap_options.parent_website_sitemap or "", as_dict=True) | |||
# determine templates to be used | |||
if not sitemap_options.base_template_path: | |||