Conflicts: webnotes/auth.py webnotes/handler.py webnotes/model/bean.py webnotes/webutils.pyversion-14
@@ -201,7 +201,7 @@ def throw(msg, exc=ValidationError): | |||
def create_folder(path): | |||
if not os.path.exists(path): os.makedirs(path) | |||
def connect(site=None, db_name=None): | |||
from db import Database | |||
if site: | |||
@@ -546,27 +546,36 @@ jenv = None | |||
def get_jenv(): | |||
global jenv | |||
if not jenv: | |||
from jinja2 import Environment, ChoiceLoader, PackageLoader | |||
from jinja2 import Environment, ChoiceLoader, PackageLoader, DebugUndefined | |||
import webnotes.utils | |||
apps = get_installed_apps() | |||
apps.remove("webnotes") | |||
# webnotes will be loaded last, so app templates will get precedence | |||
jenv = Environment(loader = ChoiceLoader([PackageLoader(app, ".") \ | |||
for app in apps + ["webnotes"]])) | |||
for app in apps + ["webnotes"]]), undefined=DebugUndefined) | |||
set_filters(jenv) | |||
jenv.globals.update({ | |||
"webnotes": sys.modules[__name__], | |||
"webnotes.utils": webnotes.utils | |||
}) | |||
return jenv | |||
def set_filters(jenv): | |||
from webnotes.utils import global_date_format | |||
from webnotes.utils import global_date_format, scrub_relative_url | |||
from webnotes.webutils import get_hex_shade | |||
from markdown2 import markdown | |||
from json import dumps | |||
jenv.filters["global_date_format"] = global_date_format | |||
jenv.filters["markdown"] = markdown | |||
jenv.filters["json"] = dumps | |||
jenv.filters["scrub_relative_url"] = scrub_relative_url | |||
jenv.filters["get_hex_shade"] = get_hex_shade | |||
# load jenv_filters from hooks.txt | |||
for app in get_all_apps(True): | |||
@@ -107,7 +107,7 @@ class LoginManager: | |||
def set_user_info(self): | |||
info = webnotes.conn.get_value("Profile", self.user, | |||
["user_type", "first_name", "last_name"], as_dict=1) | |||
["user_type", "first_name", "last_name", "user_image"], as_dict=1) | |||
if info.user_type=="Website User": | |||
webnotes.local._response.set_cookie("system_user", "no") | |||
webnotes.local.response["message"] = "No App" | |||
@@ -116,9 +116,10 @@ class LoginManager: | |||
webnotes.local.response['message'] = 'Logged In' | |||
full_name = " ".join(filter(None, [info.first_name, info.last_name])) | |||
webnotes.local.response["full_name"] = full_name | |||
webnotes.local._response.set_cookie("full_name", full_name) | |||
webnotes.local._response.set_cookie("user_id", self.user) | |||
webnotes.response["full_name"] = full_name | |||
webnotes._response.set_cookie("full_name", full_name) | |||
webnotes._response.set_cookie("user_id", self.user) | |||
webnotes._response.set_cookie("user_image", info.user_image or "") | |||
def make_session(self, resume=False): | |||
# start session | |||
@@ -237,7 +237,8 @@ def use(): | |||
# install | |||
@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): | |||
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) | |||
@@ -36,6 +36,15 @@ def make(doctype=None, name=None, content=None, subject=None, sent_or_received = | |||
if doctype and name and not webnotes.has_permission(doctype, "email", name): | |||
raise webnotes.PermissionError("You are not allowed to send emails related to: {doctype} {name}".format( | |||
doctype=doctype, name=name)) | |||
_send(doctype=doctype, name=name, content=content, subject=subject, sent_or_received=sent_or_received, | |||
sender=sender, recipients=recipients, communication_medium=communication_medium, send_email=send_email, | |||
print_html=print_html, attachments=attachments, send_me_a_copy=send_me_a_copy, set_lead=set_lead, | |||
date=date) | |||
def _make(doctype=None, name=None, content=None, subject=None, sent_or_received = "Sent", | |||
sender=None, recipients=None, communication_medium="Email", send_email=False, | |||
print_html=None, attachments='[]', send_me_a_copy=False, set_lead=True, date=None): | |||
# add to Communication | |||
sent_via = None | |||
@@ -38,7 +38,6 @@ class DocType: | |||
make_module_and_roles(self.doclist, "Page Role") | |||
if not webnotes.flags.in_import and getattr(conf,'developer_mode', 0) and self.doc.standard=='Yes': | |||
print "here" | |||
from webnotes.modules.export_file import export_to_files | |||
from webnotes.modules import get_module_path, scrub | |||
import os | |||
@@ -347,6 +347,57 @@ def reset_password(user): | |||
else: | |||
return "No such user (%s)" % user | |||
@webnotes.whitelist(allow_guest=True) | |||
def facebook_login(data): | |||
data = json.loads(data) | |||
if not (data.get("id") and data.get("fb_access_token")): | |||
raise webnotes.ValidationError | |||
user = data["email"] | |||
if not get_fb_userid(data.get("fb_access_token")): | |||
# garbage | |||
raise webnotes.ValidationError | |||
if not webnotes.conn.exists("Profile", user): | |||
if data.get("birthday"): | |||
b = data.get("birthday").split("/") | |||
data["birthday"] = b[2] + "-" + b[0] + "-" + b[1] | |||
profile = webnotes.bean({ | |||
"doctype":"Profile", | |||
"first_name": data["first_name"], | |||
"last_name": data["last_name"], | |||
"email": data["email"], | |||
"enabled": 1, | |||
"new_password": webnotes.generate_hash(data["email"]), | |||
"fb_username": data["username"], | |||
"fb_userid": data["id"], | |||
"fb_location": data.get("location", {}).get("name"), | |||
"fb_hometown": data.get("hometown", {}).get("name"), | |||
"fb_age_range": data.get("age_range") and "{min}-{max}".format(**data.get("age_range")), | |||
"birth_date": data.get("birthday"), | |||
"fb_bio": data.get("bio"), | |||
"fb_education": data.get("education") and data.get("education")[-1].get("type"), | |||
"user_type": "Website User" | |||
}) | |||
profile.ignore_permissions = True | |||
profile.get_controller().no_welcome_mail = True | |||
profile.insert() | |||
webnotes.local.login_manager.user = user | |||
webnotes.local.login_manager.post_login() | |||
def get_fb_userid(fb_access_token): | |||
import requests | |||
response = requests.get("https://graph.facebook.com/me?access_token=" + fb_access_token) | |||
if response.status_code==200: | |||
print response.json() | |||
return response.json().get("id") | |||
else: | |||
return webnotes.AuthenticationError | |||
def profile_query(doctype, txt, searchfield, start, page_len, filters): | |||
from webnotes.widgets.reportview import get_match_cond | |||
return webnotes.conn.sql("""select name, concat_ws(' ', first_name, middle_name, last_name) | |||
@@ -2,7 +2,7 @@ | |||
{ | |||
"creation": "2013-03-07 11:54:44", | |||
"docstatus": 0, | |||
"modified": "2014-01-23 13:27:37", | |||
"modified": "2014-01-29 16:52:01", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
@@ -132,15 +132,6 @@ | |||
"options": "Loading...", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "birth_date", | |||
"fieldtype": "Date", | |||
"label": "Birth Date", | |||
"oldfieldname": "birth_date", | |||
"oldfieldtype": "Date", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"default": "System User", | |||
"doctype": "DocField", | |||
@@ -154,17 +145,6 @@ | |||
"read_only": 1, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "gender", | |||
"fieldtype": "Select", | |||
"label": "Gender", | |||
"oldfieldname": "gender", | |||
"oldfieldtype": "Select", | |||
"options": "\nMale\nFemale\nOther", | |||
"permlevel": 0, | |||
"search_index": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "change_password", | |||
@@ -234,6 +214,39 @@ | |||
"label": "Short Bio", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "gender", | |||
"fieldtype": "Select", | |||
"label": "Gender", | |||
"oldfieldname": "gender", | |||
"oldfieldtype": "Select", | |||
"options": "\nMale\nFemale\nOther", | |||
"permlevel": 0, | |||
"search_index": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "birth_date", | |||
"fieldtype": "Date", | |||
"label": "Birth Date", | |||
"oldfieldname": "birth_date", | |||
"oldfieldtype": "Date", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "location", | |||
"fieldtype": "Data", | |||
"label": "Location", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "column_break_22", | |||
"fieldtype": "Column Break", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "bio", | |||
@@ -439,6 +452,29 @@ | |||
"print_hide": 1, | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "facebook_authentication", | |||
"fieldtype": "Section Break", | |||
"label": "Facebook Authentication", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "fb_username", | |||
"fieldtype": "Data", | |||
"label": "Facebook Username", | |||
"permlevel": 0, | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "fb_userid", | |||
"fieldtype": "Data", | |||
"label": "Facebook User ID", | |||
"permlevel": 0, | |||
"read_only": 1 | |||
}, | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
@@ -461,6 +497,19 @@ | |||
"role": "All", | |||
"write": 0 | |||
}, | |||
{ | |||
"create": 0, | |||
"delete": 0, | |||
"doctype": "DocPerm", | |||
"email": 1, | |||
"permlevel": 0, | |||
"print": 1, | |||
"report": 1, | |||
"restricted": 1, | |||
"role": "All", | |||
"submit": 0, | |||
"write": 0 | |||
}, | |||
{ | |||
"amend": 0, | |||
"create": 0, | |||
@@ -119,4 +119,3 @@ def get_attr(cmd): | |||
method = globals()[cmd] | |||
webnotes.log("method:" + cmd) | |||
return method | |||
@@ -6,13 +6,24 @@ app_icon = icon-cog | |||
app_version = 4.0.0-wip | |||
app_color = #3498db | |||
before_install = webnotes.utils.install.before_install | |||
after_install = webnotes.utils.install.after_install | |||
# website | |||
app_include_js = assets/js/webnotes.min.js | |||
app_include_css = assets/webnotes/css/splash.css | |||
app_include_css = assets/css/webnotes.css | |||
web_include_js = assets/js/webnotes-web.min.js | |||
web_include_css = assets/css/webnotes-web.css | |||
web_include_js = website_script.js | |||
web_include_css = style_settings.css | |||
website_clear_cache = webnotes.templates.generators.website_group.clear_cache | |||
website_group_handler:Forum = webnotes.templates.website_group.forum | |||
website_group_handler:Events = webnotes.templates.website_group.events | |||
website_group_handler:Tasks = webnotes.templates.website_group.tasks | |||
get_desktop_icons = webnotes.manage.get_desktop_icons | |||
notification_config = webnotes.core.notifications.get_notification_config | |||
@@ -26,7 +37,7 @@ on_session_creation = webnotes.auth.notify_administrator_login | |||
# permissions | |||
permission_query_conditions:Event = webnotes.core.doctype.event.event.get_permission_query_conditions | |||
has_permission:Event = webnotes.core.doctype.event.event.has_permission | |||
has_permission:Event = webnotes.core.doctype.event.event.has_permission | |||
permission_query_conditions:ToDo = webnotes.core.doctype.todo.todo.get_permission_query_conditions | |||
has_permission:ToDo = webnotes.core.doctype.todo.todo.has_permission | |||
has_permission:ToDo = webnotes.core.doctype.todo.todo.has_permission |
@@ -241,6 +241,8 @@ class Bean: | |||
return webnotes.local.response | |||
return out | |||
def get_attr(self, method): | |||
self.make_controller() | |||
return getattr(self.controller, method, None) | |||
@@ -9,10 +9,11 @@ import webnotes.defaults | |||
from webnotes.utils.file_manager import remove_all | |||
from webnotes import _ | |||
def delete_doc(doctype=None, name=None, doclist = None, force=0, ignore_doctypes=[], for_reload=False, ignore_permissions=False): | |||
def delete_doc(doctype=None, name=None, doclist = None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False): | |||
""" | |||
Deletes a doc(dt, dn) and validates if it is not submitted and not linked in a live record | |||
""" | |||
if not ignore_doctypes: ignore_doctypes = [] | |||
# get from form | |||
if not doctype: | |||
@@ -8,7 +8,7 @@ import webnotes.model.doctype | |||
from webnotes.model.doc import validate_name | |||
@webnotes.whitelist() | |||
def rename_doc(doctype, old, new, force=False, merge=False): | |||
def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False): | |||
""" | |||
Renames a doc(dt, old) to doc(dt, new) and | |||
updates all linked fields of type "Link" or "Select" with "link:" | |||
@@ -23,11 +23,9 @@ def rename_doc(doctype, old, new, force=False, merge=False): | |||
doclist = webnotes.model.doctype.get(doctype) | |||
# call before_rename | |||
old_obj = webnotes.get_obj(doctype, old) | |||
if hasattr(old_obj, 'before_rename'): | |||
new = old_obj.before_rename(old, new, merge) or new | |||
new = webnotes.bean(doctype, old).run_method("before_rename", old, new, merge) or new | |||
new = validate_rename(doctype, new, doclist, merge, force) | |||
new = validate_rename(doctype, new, doclist, merge, force, ignore_permissions) | |||
if not merge: | |||
rename_parent_and_child(doctype, old, new, doclist) | |||
@@ -45,9 +43,7 @@ def rename_doc(doctype, old, new, force=False, merge=False): | |||
webnotes.delete_doc(doctype, old) | |||
# call after_rename | |||
new_obj = webnotes.get_obj(doctype, new) | |||
if hasattr(new_obj, 'after_rename'): | |||
new_obj.after_rename(old, new, merge) | |||
webnotes.bean(doctype, new).run_method("after_rename", old, new, merge) | |||
# update restrictions | |||
webnotes.conn.sql("""update tabDefaultValue set defvalue=%s where parenttype='Restriction' | |||
@@ -71,7 +67,7 @@ def rename_parent_and_child(doctype, old, new, doclist): | |||
update_child_docs(old, new, doclist) | |||
def validate_rename(doctype, new, doclist, merge, force): | |||
def validate_rename(doctype, new, doclist, merge, force, ignore_permissions): | |||
exists = webnotes.conn.exists(doctype, new) | |||
if merge and not exists: | |||
@@ -80,7 +76,7 @@ def validate_rename(doctype, new, doclist, merge, force): | |||
if (not merge) and exists: | |||
webnotes.msgprint("%s: %s exists, select a new, new name." % (doctype, new), raise_exception=1) | |||
if not webnotes.has_permission(doctype, "write"): | |||
if not (ignore_permissions or webnotes.has_permission(doctype, "write")): | |||
webnotes.msgprint("You need write permission to rename", raise_exception=1) | |||
if not force and not doclist[0].allow_rename: | |||
@@ -9,4 +9,5 @@ execute:webnotes.reload_doc('core', 'doctype', 'report') #2013-13-26 | |||
webnotes.patches.4_0.remove_index_sitemap | |||
webnotes.patches.4_0.add_delete_permission | |||
webnotes.patches.4_0.move_match_to_restricted | |||
webnotes.patches.4_0.set_todo_checked_as_closed | |||
webnotes.patches.4_0.set_todo_checked_as_closed | |||
webnotes.patches.4_0.website_sitemap_hierarchy |
@@ -0,0 +1,22 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
def execute(): | |||
webnotes.reload_doc("website", "doctype", "website_sitemap") | |||
webnotes.reload_doc("website", "doctype", "website_sitemap_permission") | |||
webnotes.reload_doc("website", "doctype", "website_group") | |||
webnotes.reload_doc("website", "doctype", "post") | |||
webnotes.reload_doc("website", "doctype", "user_vote") | |||
webnotes.conn.sql("""update `tabWebsite Sitemap` ws set ref_doctype=(select wsc.ref_doctype | |||
from `tabWebsite Sitemap Config` wsc where wsc.name=ws.website_sitemap_config) | |||
where ifnull(page_or_generator, '')!='Page'""") | |||
home_page = webnotes.conn.get_value("Website Settings", "Website Settings", "home_page") | |||
home_page = webnotes.conn.get_value("Website Sitemap", {"docname": home_page}) or home_page | |||
webnotes.conn.set_value("Website Settings", "Website Settings", "home_page", | |||
home_page) |
@@ -7,10 +7,17 @@ | |||
], | |||
"js/webnotes-web.min.js": [ | |||
"public/js/lib/bootstrap.min.js", | |||
"public/js/wn/provide.js", | |||
"public/js/wn/misc/number_format.js", | |||
"public/js/lib/nprogress.js", | |||
"public/js/wn/translate.js", | |||
"website/js/website.js" | |||
"public/js/wn/misc/pretty_date.js", | |||
"website/js/website.js", | |||
"website/js/website_group.js" | |||
], | |||
"js/canvasResize.min.js": [ | |||
"website/js/jquery.exif.js", | |||
"website/js/jquery.canvasResize.js" | |||
], | |||
"js/editor.min.js": [ | |||
"public/js/lib/jquery/jquery.hotkeys.js", | |||
@@ -316,6 +316,11 @@ div#freeze { | |||
max-height: 15px; | |||
} | |||
.navbar-brand { | |||
min-height: 20px; | |||
height: auto; | |||
} | |||
.navbar #spinner { | |||
display: block; | |||
float: right; | |||
@@ -6,37 +6,78 @@ | |||
<title>{{ title }}</title> | |||
<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"> | |||
{% block head %} | |||
{% if meta_description -%} | |||
<meta name="description" content="{{ meta_description }}">{%- endif %} | |||
{% for link in web_include_js -%} | |||
<script type="text/javascript" src="/{{ link }}"></script> | |||
{%- endfor %} | |||
{% for link in web_include_css -%} | |||
<link type="text/css" rel="stylesheet" href="/{{ link }}"> | |||
{%- endfor %} | |||
{% endblock %} | |||
{% block javascript -%} | |||
{% if javascript %}<script>{{ javascript }}</script>{% endif %} | |||
<link rel="shortcut icon" href="{{ favicon | scrub_relative_url }}" type="image/x-icon"> | |||
<link rel="icon" href="{{ favicon | scrub_relative_url }}" type="image/x-icon"> | |||
{% block head -%} | |||
{%- if meta_description is defined -%} | |||
<meta name="description" content="{{ meta_description }}"> | |||
{%- endif -%} | |||
{%- for link in web_include_js -%} | |||
<script type="text/javascript" src="{{ link | scrub_relative_url }}"></script> | |||
{%- endfor -%} | |||
{%- for link in web_include_css -%} | |||
<link type="text/css" rel="stylesheet" href="{{ link | scrub_relative_url }}"> | |||
{%- endfor -%} | |||
{% block script -%} | |||
<script data-html-block="script"> | |||
{%- if script is defined -%}{{ script }}{%- endif -%} | |||
</script> | |||
{%- endblock %} | |||
{% block style -%} | |||
<style data-html-block="style"> | |||
{%- if style is defined -%}{{ style }}{%- endif -%} | |||
</style> | |||
{%- endblock %} | |||
{%- endblock %} | |||
{% block css -%} | |||
{% if css %}<style>{{ css }}</style>{% endif %} | |||
{%- endblock %} | |||
{% block style -%}{%- endblock %} | |||
</head> | |||
<body> | |||
{% block banner %} | |||
{% if banner_html -%} | |||
<header class="container">{{ banner_html or "" }}</header> | |||
{%- endif %} | |||
{% endblock %} | |||
{% block navbar %}{% include "templates/includes/navbar.html" %}{% endblock %} | |||
<div class="page-container" id="page-{{ name }}"> | |||
{% block content %}{% endblock %} | |||
<div id="wrap"> | |||
{%- block banner -%} | |||
{% if banner_html -%} | |||
<header class="container">{{ banner_html or "" }}</header> | |||
{%- endif %} | |||
{%- endblock -%} | |||
{%- block navbar -%}{% include "templates/includes/navbar.html" %}{%- endblock -%} | |||
<header class="page-header"> | |||
<div class="container" data-html-block="header"> | |||
{%- if header is defined -%}{{ header }}{%- endif -%} | |||
</div> | |||
</header> | |||
<header class="page-breadcrumbs"> | |||
<div class="container" data-html-block="breadcrumbs"> | |||
{%- if breadcrumbs is defined -%}{{ breadcrumbs }}{%- endif -%} | |||
</div> | |||
</header> | |||
<div class="container page-container" id="page-{{ name or page_name }}"> | |||
<div class="row"> | |||
<div class="col-sm-3 col-sm-push-9 page-sidebar hidden-xs" data-html-block="sidebar"> | |||
{%- block sidebar -%}{%- if sidebar is defined -%}{{ sidebar }}{%- endif -%}{%- 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> | |||
</div> | |||
<footer class="page-footer"> | |||
<div class="container" data-html-block="footer"> | |||
{%- if footer is defined -%}{{ footer }}{%- endif -%} | |||
</div> | |||
</footer> | |||
</div> | |||
<div id="wrap-footer"> | |||
{%- block footer -%}{% include "templates/includes/footer.html" %}{%- endblock -%} | |||
</div> | |||
{% block footer %}{% include "templates/includes/footer.html" %}{% endblock %} | |||
{% block script -%}{%- endblock %} | |||
</body> | |||
</html> |
@@ -1,9 +1,13 @@ | |||
{% extends base_template %} | |||
{% block title %} {{ title }} {% endblock %} | |||
{% block content %} | |||
<div class="container content" itemscope itemtype="http://schema.org/BlogPost"> | |||
<h2 itemprop="name headline">{{ title }}</h2> | |||
{% block header %} | |||
<h2 itemprop="name headline" itemscope itemtype="http://schema.org/BlogPost"> | |||
{{ title }} | |||
</h2> | |||
{% endblock %} | |||
{% block content %} | |||
<div class="blog-content" itemscope itemtype="http://schema.org/BlogPost"> | |||
<!-- begin blog content --> | |||
<div class="help" style="color: #aaa"> | |||
<span itemprop="author">{{ blogger_info and blogger_info.full_name or full_name }}</span> / | |||
@@ -31,5 +35,8 @@ $(function() { | |||
} | |||
}); | |||
</script> | |||
{% include 'templates/includes/blog_footer.html' %} | |||
{% endblock %} | |||
{% endblock %} | |||
{% block footer %}{% include 'templates/includes/blog_footer.html' %}{% endblock %} | |||
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} |
@@ -1,2 +1,72 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import markdown2 | |||
import webnotes | |||
from webnotes.utils import global_date_format, get_fullname, cint | |||
from webnotes.webutils import render_blocks | |||
doctype = "Blog Post" | |||
condition_field = "published" | |||
condition_field = "published" | |||
def get_context(context): | |||
blog_post = webnotes.doc(context.ref_doctype, context.docname) | |||
# this is for double precaution. usually it wont reach this code if not published | |||
if not cint(blog_post.published): | |||
raise Exception, "This blog has not been published yet!" | |||
# temp fields | |||
blog_post.full_name = get_fullname(blog_post.owner) | |||
blog_post.updated = global_date_format(blog_post.published_on) | |||
if blog_post.blogger: | |||
blog_post.blogger_info = webnotes.doc("Blogger", blog_post.blogger).fields | |||
blog_post.description = blog_post.blog_intro or blog_post.content[:140] | |||
blog_post.meta_description = blog_post.description | |||
blog_post.categories = webnotes.conn.sql_list("select name from `tabBlog Category` order by name") | |||
blog_post.comment_list = webnotes.conn.sql("""\ | |||
select comment, comment_by_fullname, creation | |||
from `tabComment` where comment_doctype="Blog Post" | |||
and comment_docname=%s order by creation""", (blog_post.name,), as_dict=1) or [] | |||
blog_post.fields.update(context) | |||
return render_blocks(blog_post.fields) | |||
@webnotes.whitelist(allow_guest=True) | |||
def get_blog_list(start=0, by=None, category=None): | |||
condition = "" | |||
if by: | |||
condition = " and t1.blogger='%s'" % by.replace("'", "\'") | |||
if category: | |||
condition += " and t1.blog_category='%s'" % category.replace("'", "\'") | |||
query = """\ | |||
select | |||
t1.title, t1.name, t1.page_name, t1.published_on as creation, | |||
ifnull(t1.blog_intro, t1.content) as content, | |||
t2.full_name, t2.avatar, t1.blogger, | |||
(select count(name) from `tabComment` where | |||
comment_doctype='Blog Post' and comment_docname=t1.name) as comments | |||
from `tabBlog Post` t1, `tabBlogger` t2 | |||
where ifnull(t1.published,0)=1 | |||
and t1.blogger = t2.name | |||
%(condition)s | |||
order by published_on desc, name asc | |||
limit %(start)s, 20""" % {"start": start, "condition": condition} | |||
result = webnotes.conn.sql(query, as_dict=1) | |||
# strip html tags from content | |||
for res in result: | |||
res['published'] = global_date_format(res['creation']) | |||
if not res['content']: | |||
res['content'] = webnotes.webutils.get_html(res['page_name']) | |||
res['content'] = res['content'][:140] | |||
return result |
@@ -1,10 +1,11 @@ | |||
{% extends base_template %} | |||
{% block title %} {{ title }} {% endblock %} | |||
{% block header %}{% if show_title %}<h2>{{ title }}</h2>{% endif %}{% endblock %} | |||
{% block content %} | |||
<div class="container content"> | |||
<div class="webpage-content"> | |||
{# title, breadcrumbs, table of contents #} | |||
{% block pre_content -%} | |||
{% if show_title %}<h1>{{ title }}</h1>{% endif %} | |||
{% if show_breadcrumbs and breadcrumbs -%} | |||
<ul class="breadcrumb"> | |||
{% for b in breadcrumbs -%} | |||
@@ -65,3 +66,9 @@ $(function() { | |||
}); | |||
</script> | |||
{% endblock %} | |||
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} | |||
{% block style %}{{ style }}{% endblock %} | |||
{% block script %}{{ script }}{% endblock %} |
@@ -1,2 +1,94 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import render_blocks | |||
from webnotes.website.doctype.website_slideshow.website_slideshow import get_slideshow | |||
doctype = "Web Page" | |||
condition_field = "published" | |||
condition_field = "published" | |||
def get_context(context): | |||
web_page = webnotes.bean(context.ref_doctype, context.docname) | |||
if web_page.doc.slideshow: | |||
web_page.doc.fields.update(get_slideshow(web_page)) | |||
web_page.doc.meta_description = web_page.doc.description | |||
web_page.doc.breadcrumbs = get_breadcrumbs(web_page) | |||
web_page.doc.toc_list = get_toc_list(web_page) | |||
# parent, child, next sibling links | |||
web_page.doc.links = get_navigation_links(web_page) | |||
if web_page.doc.enable_comments: | |||
web_page.doc.comment_list = webnotes.conn.sql("""select | |||
comment, comment_by_fullname, creation | |||
from `tabComment` where comment_doctype="Web Page" | |||
and comment_docname=%s order by creation""", web_page.doc.name, as_dict=1) or [] | |||
web_page.doc.fields.update({ | |||
"style": web_page.doc.css or "", | |||
"script": web_page.doc.javascript or "" | |||
}) | |||
web_page.doc.fields.update(context) | |||
return render_blocks(web_page.doc.fields) | |||
def get_breadcrumbs(web_page): | |||
breadcrumbs = [] | |||
def add_parent_of(web_page): | |||
parent = webnotes.conn.sql("""select name, page_name, title from `tabWeb Page` | |||
where exists (select parent from `tabTable of Contents` | |||
where `tabTable of Contents`.parent=`tabWeb Page`.name | |||
and web_page=%s)""", web_page, as_dict=True) | |||
if parent and parent[0]: | |||
parent = parent[0] | |||
add_parent_of(parent.name) | |||
breadcrumbs.append(parent) | |||
add_parent_of(web_page.doc.name) | |||
return breadcrumbs | |||
def get_toc_list(web_page): | |||
toc_list = web_page.doclist.get({"parentfield": "toc"}) | |||
if not toc_list: return [] | |||
out = webnotes.conn.sql("""select name, page_name, title | |||
from `tabWeb Page` where name in (%s)""" % \ | |||
(", ".join(["%s"]*len(toc_list))), | |||
tuple([d.web_page for d in toc_list]), | |||
as_dict=True) | |||
toc_idx = dict(((toc.web_page, toc.idx) for toc in toc_list)) | |||
return sorted(out, key=lambda x: toc_idx.get(x.name)) | |||
def get_navigation_links(web_page): | |||
links = {} | |||
if web_page.doc.toc_list: | |||
links["child"] = web_page.doc.toc_list[0] | |||
if web_page.doc.breadcrumbs: | |||
if web_page.doc.breadcrumbs[-1]: | |||
links["parent"] = web_page.doc.breadcrumbs[-1] | |||
def set_next(current, parent, breadcrumbs): | |||
web_page = webnotes.get_obj("Web Page", parent) | |||
toc_list = web_page.get_toc_list() | |||
for i, toc in enumerate(toc_list): | |||
if toc.name == current and ((i+1)<len(toc_list)): | |||
links["next"] = toc_list[i+1] | |||
break | |||
if not links.get("next") and breadcrumbs: | |||
set_next(parent, breadcrumbs[-1].name, breadcrumbs[:-1]) | |||
set_next(web_page.doc.name, web_page.doc.breadcrumbs[-1].name, web_page.doc.breadcrumbs[:-1]) | |||
return links |
@@ -0,0 +1,42 @@ | |||
{% block title %}{{ title }}{% endblock %} | |||
{% block header %} | |||
<h2>{{ group.group_title }}</h2> | |||
{%- if group.group_description -%} | |||
<p class="lead">{{ group.group_description }}</p> | |||
{%- endif -%} | |||
{% endblock %} | |||
{% block breadcrumbs %} | |||
<ul class="breadcrumb"> | |||
{% for parent in parents %} | |||
<li><a href="/{{ parent.name|lower }}">{{ parent.page_title }}</a></li> | |||
{% endfor %} | |||
<li class="active">{{ title }}</li> | |||
</ul> | |||
{% endblock %} | |||
{% block content %} | |||
<ul class="nav nav-tabs view-selector"> | |||
{%- for t in views -%} | |||
<li class="{% if view.name==t.name -%} active {%- endif %} {% if t.hidden -%} hide {%- endif %}" | |||
data-view="{{ t.name }}"> | |||
<a href="{{ t.url or '' }}"><i class="{{ t.icon }}"></i> | |||
<span class="nav-label">{{ t.label }}</span></a> | |||
</li> | |||
{%- endfor -%} | |||
</ul> | |||
<script> | |||
{%- if access -%} | |||
website.access = {{ access|json }}; | |||
{%- endif -%} | |||
website.group = "{{ group.name }}"; | |||
website.view = "{{ view.name }}"; | |||
</script> | |||
{% include view.template_path %} | |||
{% endblock %} | |||
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} |
@@ -0,0 +1,124 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
import webnotes | |||
from webnotes.webutils import get_access, render_blocks, can_cache | |||
from webnotes.templates.website_group.post import clear_post_cache | |||
doctype = "Website Group" | |||
no_cache = 1 | |||
def get_context(context): | |||
bean = webnotes.bean(context.ref_doctype, context.docname) | |||
group, view = guess_group_view(bean, context) | |||
try: | |||
if not has_access(group, view): | |||
raise webnotes.PermissionError | |||
group_context = get_group_context(group, view, bean) | |||
group_context["access"] = get_access(group) | |||
group_context.update(context) | |||
return render_blocks(group_context) | |||
except webnotes.DoesNotExistError: | |||
return { | |||
"content": '<div class="alert alert-danger full-page">' | |||
'The page you are looking for does not exist.</div>' | |||
} | |||
except webnotes.PermissionError: | |||
return { | |||
"content": '<div class="alert alert-danger full-page">' | |||
'You are not permitted to view this page.</div>' | |||
} | |||
def get_group_context(group, view, bean): | |||
cache_key = "website_group_context:{}:{}".format(group, view) | |||
views = get_views(bean.doc.group_type) | |||
view = webnotes._dict(views.get(view)) | |||
if can_cache(view.get("no_cache")): | |||
group_context = webnotes.cache().get_value(cache_key) | |||
if group_context: | |||
return group_context | |||
group_context = build_group_context(group, view, bean, views) | |||
if can_cache(view.get("no_cache")): | |||
webnotes.cache().set_value(cache_key, group_context) | |||
return group_context | |||
def build_group_context(group, view, bean, views): | |||
title = "{} - {}".format(bean.doc.group_title, view.get("label")) | |||
for name, opts in views.iteritems(): | |||
opts["url"] = opts["url"].format(group=group, post="") | |||
group_context = webnotes._dict({ | |||
"group": bean.doc.fields, | |||
"view": view, | |||
"views": (v[1] for v in sorted(views.iteritems(), key=lambda (k, v): v.get("idx"))), | |||
"title": title | |||
}) | |||
handler = get_handler(bean.doc.group_type) | |||
if handler: | |||
group_context.update(handler.get_context(group_context)) | |||
return group_context | |||
def guess_group_view(bean, context): | |||
group = context.docname | |||
view = webnotes.form_dict.view | |||
if not view: | |||
for v, opts in get_views(bean.doc.group_type).iteritems(): | |||
if opts.get("default"): | |||
view = v | |||
break | |||
return group, view | |||
def get_handler(group_type): | |||
handler = webnotes.get_hooks("website_group_handler:{}".format(group_type)) | |||
if handler: | |||
return webnotes.get_module(handler[0]) | |||
def get_views(group_type): | |||
from copy import deepcopy | |||
handler = get_handler(group_type) | |||
if handler and hasattr(handler, "get_views"): | |||
return deepcopy(handler.get_views() or {}) | |||
return {} | |||
def has_access(group, view): | |||
access = get_access(group) | |||
if view=="settings": | |||
return access.get("admin") | |||
elif view in ("add", "edit"): | |||
return access.get("write") | |||
else: | |||
return access.get("read") | |||
def clear_cache(page_name=None, website_group=None): | |||
if page_name or website_group: | |||
filters = {"page_name": page_name} if page_name else website_group | |||
website_group = webnotes.conn.get_value("Website Group", filters, | |||
["page_name", "group_type"], as_dict=True) | |||
if not website_group: | |||
return | |||
website_groups = [website_group] | |||
else: | |||
clear_post_cache() | |||
website_groups = webnotes.conn.sql("""select page_name, group_type from `tabWebsite Group`""", as_dict=True) | |||
cache = webnotes.cache() | |||
for group in website_groups: | |||
for view in get_views(group.group_type): | |||
cache.delete_value("website_group_context:{}:{}".format(group.page_name, view)) |
@@ -1,7 +0,0 @@ | |||
<style> | |||
h2 > a, h2 > a:link, h2 > a:visited, h2 > a:active, | |||
h2 > a:hover, h2 > a:focus { | |||
text-decoration: none; | |||
color: inherit; | |||
} | |||
</style> |
@@ -3,24 +3,6 @@ | |||
// js inside blog page | |||
$(document).ready(function() { | |||
// make list of blogs | |||
blog.get_list(); | |||
$("#next-page").click(function() { | |||
blog.get_list(); | |||
}) | |||
if(get_url_arg("by_name")) { | |||
$("#blot-subtitle").html("Posts by " + get_url_arg("by_name")).toggle(true); | |||
} | |||
if(get_url_arg("category")) { | |||
$("#blot-subtitle").html("Posts filed under " + get_url_arg("category")).toggle(true); | |||
} | |||
}); | |||
var blog = { | |||
start: 0, | |||
get_list: function() { | |||
@@ -28,7 +10,7 @@ var blog = { | |||
method: "GET", | |||
url: "/", | |||
data: { | |||
cmd: "webnotes.website.doctype.blog_post.blog_post.get_blog_list", | |||
cmd: "webnotes.templates.generators.blog_post.get_blog_list", | |||
start: blog.start, | |||
by: get_url_arg("by"), | |||
category: get_url_arg("category") | |||
@@ -55,6 +37,7 @@ var blog = { | |||
} | |||
b.page_name = encodeURIComponent(b.page_name); | |||
b.avatar = b.avatar || ""; | |||
$(repl('<div class="row">\ | |||
<div class="col-md-1">\ | |||
@@ -63,10 +46,10 @@ var blog = { | |||
</div>\ | |||
</div>\ | |||
<div class="col-md-11">\ | |||
<h4><a href="%(page_name)s">%(title)s</a></h4>\ | |||
<h4><a href="/%(page_name)s">%(title)s</a></h4>\ | |||
<p>%(content)s</p>\ | |||
<p style="color: #aaa; font-size: 90%">\ | |||
<a href="blog?by=%(blogger)s&by_name=%(full_name)s">\ | |||
<a href="/blog?by=%(blogger)s&by_name=%(full_name)s">\ | |||
%(full_name)s</a> wrote this on %(published)s / %(comment_text)s</p>\ | |||
</div>\ | |||
</div><hr>', b)).appendTo($wrap); | |||
@@ -84,4 +67,22 @@ var blog = { | |||
$("#next-page").toggle(true); | |||
} | |||
} | |||
} | |||
}; | |||
$(document).ready(function() { | |||
// make list of blogs | |||
blog.get_list(); | |||
$("#next-page").click(function() { | |||
blog.get_list(); | |||
}) | |||
if(get_url_arg("by_name")) { | |||
$("#blot-subtitle").html("Posts by " + get_url_arg("by_name")).toggle(true); | |||
} | |||
if(get_url_arg("category")) { | |||
$("#blot-subtitle").html("Posts filed under " + get_url_arg("category")).toggle(true); | |||
} | |||
}); |
@@ -1,13 +1,14 @@ | |||
<div class="container content"> | |||
<hr /> | |||
{% if categories %} | |||
<h5>Explore posts by categories</h5> | |||
<ul class="breadcrumb" style="background-color: transparent; padding-left: 20px;"> | |||
{% for category in webnotes.conn.sql_list("select name from `tabBlog Category` order by name") %} | |||
<li><a href="blog?category={{ category }}">{{ category }}</a> | |||
{% endfor %} | |||
</ul> | |||
<br><br> | |||
{% endif %} | |||
<p>Show posts by <a href="blog">everyone</a>. Meet the <a href="writers">writers</a> of this blog</p> | |||
<div class="blog-footer"> | |||
<p> | |||
{% if categories %} | |||
<h5>Explore posts by categories</h5> | |||
<ul class="breadcrumb" style="background-color: transparent; padding-left: 20px;"> | |||
{% for category in webnotes.conn.sql_list("select name from `tabBlog Category` order by name") %} | |||
<li><a href="/blog?category={{ category }}">{{ category }}</a> | |||
{% endfor %} | |||
</ul> | |||
<br><br> | |||
{% endif %} | |||
<p>Show posts by <a href="/blog">everyone</a>. Meet the <a href="/writers">writers</a> of this blog</p> | |||
</p> | |||
</div> |
@@ -1,9 +0,0 @@ | |||
<h4>Subscribe</h4> | |||
<br> | |||
<p> | |||
<button class="btn btn-warning btn-blog-subscribe">Get Updates via Email</button> | |||
</p> | |||
<p> | |||
<img src="images/feed.png" style="margin-right: 4px; margin-bottom: -4px"> | |||
<a href="rss.xml" target="_blank">RSS Feed</a> | |||
</p> |
@@ -1,13 +1,13 @@ | |||
<div class="row"> | |||
<div class="col-md-2"> | |||
<div class="avatar avatar-large"> | |||
<img itemprop="thumbnailUrl" src="{{ blogger_info.avatar }}" /> | |||
<img itemprop="thumbnailUrl" src="{{ blogger_info.avatar | scrub_relative_url }}" /> | |||
</div> | |||
</div> | |||
<div class="col-md-10"> | |||
<h4>{{ blogger_info.full_name }}</h4> | |||
<p style="color: #999">{{ blogger_info.bio }}</p> | |||
<p><a href="blog?by={{ blogger_info.name }}&by_name={{ blogger_info.full_name }}"> | |||
<p><a href="/blog?by={{ blogger_info.name }}&by_name={{ blogger_info.full_name }}"> | |||
All Posts By {{ blogger_info.full_name }}</a></p> | |||
</div> | |||
</div> |
@@ -5,7 +5,7 @@ | |||
<div class="col-xs-9 web-footer-menu"> | |||
<ul class="list-inline"> | |||
{% for item in footer_items %} | |||
<li><a href="{{ item.url }}" {{ item.target }} | |||
<li><a href="{{ item.url | scrub_relative_url }}" {{ item.target }} | |||
data-label="{{ item.label }}">{{ item.label }}</a></li> | |||
{% endfor %} | |||
</ul> | |||
@@ -0,0 +1,57 @@ | |||
{% set post_url = "/" + post.website_group + "?view=post&name=" + post.name %} | |||
{% set edit_url = "/" + post.website_group + "?view=edit&name=" + post.name %} | |||
<div class="media post {% if post.parent_post -%} child-post {%- endif %}" | |||
data-name="{{ post.name }}" | |||
data-group="{{ post.website_group }}" | |||
itemscope itemtype="http://schema.org/Article"> | |||
<a class="pull-left media-link" href="{{ post_url }}"> | |||
<img class="media-object post-avatar" src="{{ post.user_image|scrub_relative_url }}"> | |||
</a> | |||
<div class="media-body"> | |||
{%- if not post.parent_post -%} | |||
<h4 class="media-heading" itemprop="headline"> | |||
{%- if view != "post" -%} | |||
<a class="no-decoration" | |||
href="{{ post_url }}">{{ post.title }}</a> | |||
{%- else -%} | |||
{{ post.title }} | |||
{%- endif -%} | |||
</h4> | |||
{%- endif -%} | |||
<ul class="list-inline small text-muted post-options"> | |||
{% if view and view.upvote %}<li class="upvote"> | |||
<a><span class="upvote-count {% if not post.upvotes %}hide{% endif %}">{{ post.upvotes }}</span> | |||
<i class="icon-thumbs-up"></i></a></li>{% endif %} | |||
{%- if not post.parent_post and view.name != "post" -%} | |||
<li><a itemprop="url" href="{{ post_url }}"> | |||
{% if not post.post_reply_count -%} | |||
<i class="icon-reply"></i> Reply | |||
{% elif post.post_reply_count == 1 %} | |||
{{ post.post_reply_count }} Reply | |||
{% else %} | |||
{{ post.post_reply_count }} Replies | |||
{%- endif %} | |||
</a></li> | |||
{%- endif -%} | |||
<li><span class="wn-timestamp" data-timestamp="{{ post.creation }}"></span></li> | |||
<li>by <span itemprop="author">{{ post.first_name or "" }} {{ post.last_name or "" }}</span></li> | |||
<li class="edit-post pull-right hide" data-owner="{{ post.owner }}"> | |||
<a class="text-muted" href="{{ edit_url }}">[edit]</a> | |||
</li> | |||
</ul> | |||
<div itemprop="articleBody" class="post-content"> | |||
{%- if post.is_task==1 and post.assigned_to -%} | |||
<span class="label label-info assigned-label"> | |||
<i class="icon-pencil"></i> {{ post.assigned_to_fullname }}</span> | |||
{%- elif post.is_event==1 and post.event_datetime -%} | |||
<span class="label label-info event-label"><i class="icon-calendar"></i> | |||
<span class="event-timestamp" data-timestamp="{{ post.event_datetime }}"></span></span> | |||
{%- endif -%} | |||
{{ post.content|markdown }} | |||
{%- if post.picture_url -%} | |||
<img src="{{ post.picture_url|scrub_relative_url }}" class="img-responsive post-picture" /> | |||
{%- endif -%} | |||
</div> | |||
</div> | |||
</div> |
@@ -1,20 +1,6 @@ | |||
var disable_signup = {{ disable_signup and "true" or "false" }}; | |||
var login = {}; | |||
$(document).ready(function(wrapper) { | |||
window.location.hash = "#login"; | |||
login.login(); | |||
$('#login_btn').click(login.do_login); | |||
$('#pass').keypress(function(ev){ | |||
if(ev.which==13 && $('#pass').val()) { | |||
$("#login_btn").click(); | |||
} | |||
}); | |||
$(document).trigger('login_rendered'); | |||
}) | |||
$(window).on("hashchange", function() { | |||
var route = window.location.hash.slice(1); | |||
if(!route) route = "login"; | |||
@@ -62,26 +48,7 @@ login.do_login = function(){ | |||
url: "/", | |||
data: args, | |||
dataType: "json", | |||
statusCode: { | |||
200: function(data) { | |||
if(data.message=="Logged In") { | |||
window.location.href = "app"; | |||
} else if(data.message=="No App") { | |||
if(localStorage) { | |||
var last_visited = localStorage.getItem("last_visited") || "index"; | |||
localStorage.removeItem("last_visited"); | |||
window.location.href = last_visited; | |||
} else { | |||
window.location.href = "index"; | |||
} | |||
} else if(window.is_sign_up) { | |||
wn.msgprint(data.message); | |||
} | |||
}, | |||
401: function(xhr, data) { | |||
login.set_message("Invalid Login"); | |||
} | |||
} | |||
statusCode: login.login_handlers | |||
}).always(function(){ | |||
$("#login-spinner").toggle(false); | |||
$('#login_btn').prop("disabled", false); | |||
@@ -140,4 +107,101 @@ login.set_message = function(message, color) { | |||
wn.msgprint(message); | |||
return; | |||
//$('#login_message').html(message).toggle(true); | |||
} | |||
} | |||
login.login_handlers = { | |||
200: function(data) { | |||
if(data.message=="Logged In") { | |||
window.location.href = "app"; | |||
} else if(data.message=="No App") { | |||
if(localStorage) { | |||
var last_visited = localStorage.getItem("last_visited") || "/index"; | |||
localStorage.removeItem("last_visited"); | |||
window.location.href = last_visited; | |||
} else { | |||
window.location.href = "/index"; | |||
} | |||
} else if(window.is_sign_up) { | |||
wn.msgprint(data.message); | |||
} | |||
}, | |||
401: function(xhr, data) { | |||
login.set_message("Invalid Login"); | |||
} | |||
} | |||
{% if fb_app_id is defined -%} | |||
// facebook login | |||
$(document).ready(function() { | |||
var user_id = wn.get_cookie("user_id"); | |||
var sid = wn.get_cookie("sid"); | |||
// logged in? | |||
if(!sid || sid==="Guest") { | |||
// fallback on facebook login -- no login again | |||
$(".btn-login").html("Login via Facebook").removeAttr("disabled"); | |||
} else { | |||
// get private stuff (if access) | |||
// app.setup_user({"user": user_id}); | |||
} | |||
}); | |||
$(function() { | |||
$login = $(".btn-login").prop("disabled", true); | |||
$.getScript('//connect.facebook.net/en_UK/all.js', function() { | |||
$login.prop("disabled", false); | |||
FB.init({ | |||
appId: '{{ fb_app_id }}', | |||
}); | |||
$login.click(function() { | |||
$login.prop("disabled", true).html("Logging In..."); | |||
login.via_facebook(); | |||
}); | |||
}); | |||
}); | |||
login.via_facebook = function() { | |||
// not logged in to facebook either | |||
FB.login(function(response) { | |||
if (response.authResponse) { | |||
// yes logged in via facebook | |||
console.log('Welcome! Fetching your information.... '); | |||
var fb_access_token = response.authResponse.accessToken; | |||
// get user graph | |||
FB.api('/me', function(response) { | |||
response.fb_access_token = fb_access_token || "[none]"; | |||
$.ajax({ | |||
url:"/", | |||
type: "POST", | |||
data: { | |||
cmd:"webnotes.core.doctype.profile.profile.facebook_login", | |||
data: JSON.stringify(response) | |||
}, | |||
statusCode: login.login_handlers | |||
}) | |||
}); | |||
} else { | |||
wn.msgprint("You have denied access to this application via Facebook. \ | |||
Please change your privacy settings in Facebook and try again. \ | |||
If you do not want to use Facebook login, <a href='/login'>sign-up</a> here"); | |||
} | |||
},{scope:"email"}); | |||
} | |||
{%- endif %} | |||
$(document).ready(function(wrapper) { | |||
window.location.hash = "#login"; | |||
login.login(); | |||
$('#login_btn').click(login.do_login); | |||
$('#pass').keypress(function(ev){ | |||
if(ev.which==13 && $('#pass').val()) { | |||
$("#login_btn").click(); | |||
} | |||
}); | |||
$(document).trigger('login_rendered'); | |||
}) |
@@ -1,15 +1,17 @@ | |||
<header> | |||
<div class="navbar navbar-default"> | |||
<nav class="navbar navbar-default" role="navigation"> | |||
<div class="container"> | |||
<div class="navbar-header"> | |||
<button type="button" class="navbar-toggle" data-toggle="collapse" | |||
data-target=".navbar-responsive-collapse"> | |||
<span class="sr-only">Toggle navigation</span> | |||
<span class="icon-bar"></span> | |||
<span class="icon-bar"></span> | |||
<span class="icon-bar"></span> | |||
</button> | |||
<a class="navbar-brand ellipsis" href="index"><span>{{ brand_html or "<i class='icon-home'></i>"}}</span></a> | |||
<span class="clearfix"></span> | |||
<a class="navbar-brand ellipsis" href="/"> | |||
<span>{{ brand_html or "<i class='icon-home'></i>"}}</span> | |||
</a> | |||
</div> | |||
<div class="collapse navbar-collapse navbar-responsive-collapse"> | |||
{% if top_bar_items -%} | |||
@@ -17,7 +19,7 @@ | |||
{%- for page in top_bar_items -%} | |||
{% if not page.parent_label -%} | |||
<li data-label="{{ page.label }}" {% if page.child_items %} class="dropdown"{% endif %}> | |||
<a href="{{ page.url or '#' }}" {% if page.child_items %} class="dropdown-toggle" onclick="return false;" data-toggle="dropdown"{% endif %} {{ page.target or ''}}> | |||
<a href="{{ page.url | scrub_relative_url }}" {% if page.child_items %} class="dropdown-toggle" onclick="return false;" data-toggle="dropdown"{% endif %} {{ page.target or ''}}> | |||
{{ page.label }} | |||
{%- if page.child_items -%} | |||
<span class="caret"></span> | |||
@@ -26,7 +28,7 @@ | |||
{%- for child in page.child_items -%} | |||
<li data-label="{{ child.label }}"> | |||
<a {% if child.indent %} style="padding-left: {{((child.indent|int)+1)*15 }}px"{% endif %} | |||
href="{{ child.url }}" {{ child.target or '' }}>{{ child.label }}</a> | |||
href="{{ child.url | scrub_relative_url }}" {{ child.target or '' }}>{{ child.label }}</a> | |||
</li> | |||
{%- endfor -%} | |||
</ul> | |||
@@ -38,28 +40,37 @@ | |||
{%- endfor %} | |||
</ul> | |||
{%- endif %} | |||
<ul class="nav navbar-nav navbar-right"> | |||
<ul class="logged-in nav navbar-nav navbar-right" style="display: none;"> | |||
<!-- post login tools --> | |||
<li id="website-post-login" data-label="website-post-login" class="dropdown"> | |||
<a href="#" class="dropdown-toggle" onclick="return false;" data-toggle="dropdown"> | |||
<i class="icon-cog"></i><span class="visible-xs-inline"><span class="caret"></span></span> | |||
<li class="dropdown" id="website-post-login" data-label="website-post-login"> | |||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"> | |||
<img class="user-picture" style="min-width: 20px; max-height: 20px; border-radius: 4px"/> | |||
<b class="full-name"></b><b class="caret"></b> | |||
</a> | |||
<ul class="dropdown-menu"> | |||
<ul class="dropdown-menu"> | |||
{%- for child in post_login -%} | |||
<li data-label="{{ child.label }}" {% if child.class %}class="{{ child.class }}"{% endif %}> | |||
{% if child.url -%} | |||
<a href="{{ child.url }}" {{ child.target or '' }}> | |||
{% if child.icon %}<i class="icon-fixed-width {{ child.icon }}"></i> {% endif %} | |||
{{ child.label }} | |||
</a> | |||
{%- endif %} | |||
<li data-label="{{ child.label }}" | |||
{% if child.class %} class="{{ child.class }}" {% endif %}> | |||
{%- if child.url -%} | |||
<a href="{{ child.url | scrub_relative_url }}" {{ child.target or '' }}> | |||
{%- if child.icon -%} | |||
<i class="icon-fixed-width {{ child.icon }}"></i> | |||
{%- endif -%} | |||
{{ child.label }} | |||
</a> | |||
{%- endif -%} | |||
</li> | |||
{%- endfor -%} | |||
</ul> | |||
</li> | |||
</ul> | |||
<ul class="btn-login-area nav navbar-nav navbar-right"> | |||
<li><a href="/login">Sign Up / Login</a></li> | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
</nav> | |||
</header> | |||
<script>$('.dropdown-toggle').dropdown()</script> |
@@ -0,0 +1,66 @@ | |||
{% set parent_post = post.parent_post if post else parent_post %} | |||
<div class="post-editor well" | |||
{% if parent_post %}data-parent-post="{{ parent_post }}"{% endif %} | |||
{% if post %}data-post="{{ post.name }}"{% endif %}> | |||
{%- if not (post and post.parent_post) and not parent_post-%} | |||
<input type="text" class="form-group form-control h3" placeholder="Title" | |||
data-fieldname="title" {%- if post and post.title -%}value="{{ post.title }}"{%- endif -%}> | |||
{%- endif -%} | |||
<textarea class="form-group form-control post-add-textarea" placeholder="Enter text" | |||
data-fieldname="content">{%- if post and post.content -%}{{ post.content }}{%- endif -%}</textarea> | |||
<!-- task and events related fields --> | |||
{%- if view.name != "post" and not (post and post.parent_post) -%} | |||
{%- if group.group_type == "Tasks" -%} | |||
<input type="text" class="form-group form-control control-assign" | |||
placeholder="Assign this task to someone" | |||
{%- if post and post.assigned_to_fullname -%}value="{{ post.assigned_to_fullname }}"{%- endif -%} /> | |||
<input type="hidden" class="form-group form-control hide" data-fieldname="assigned_to" | |||
{% if post and post.assigned_to %}value="{{ post.assigned_to }}"{% endif %}/> | |||
<div class="assigned-to alert alert-success {% if not (post and post.assigned_to) %}hide{% endif %}" | |||
style="margin: 10px 0px;"> | |||
<div class="row"> | |||
<div class="col-xs-10"> | |||
<div class="assigned-profile user-profile"> | |||
{%- if post and profile -%} | |||
{% include "templates/includes/profile_display.html" %} | |||
{%- endif -%} | |||
</div> | |||
</div> | |||
<div class="col-xs-2"> | |||
<a class="close">×</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="form-group task-status {% if not (post and post.assigned_to) %}hide{% endif %}"> | |||
<label>Status</label> | |||
<select class="form-control" data-fieldname="status"> | |||
{% for opt in ("Open", "Closed") %} | |||
<option value="{{ opt }}" {% if post and opt==post.status %}selected{% endif %}>{{ opt }}</option> | |||
{% endfor %} | |||
</select> | |||
</div> | |||
{%- elif group.group_type == "Events" -%} | |||
<input type="text" class="form-group form-control control-event" | |||
placeholder="Enter Event Date and Time" /> | |||
<input type="hidden" class="form-group form-control hide" data-fieldname="event_datetime" | |||
{% if post and post.event_datetime %}value="{{ post.event_datetime }}"{% endif %}/> | |||
{%- endif -%} | |||
{%- endif -%} | |||
<div class="text-muted small">tab + enter to post / <a target="_blank" class="text-muted" | |||
href="/markdown-cheatsheet" tabindex="-1">markdown formatting</a></div> | |||
<div class="post-picture hide" style="margin: 10px 0px;"> | |||
<img src="{{ post.picture_url|scrub_relative_url if post else ''}}" class="img-responsive" /> | |||
</div> | |||
<div class="clearfix"> | |||
<button class="btn btn-default btn-post-add pull-right"><i class="icon-plus"></i> Add Post</button> | |||
<button class="btn btn-default btn-post-save pull-right hide"><i class="icon-ok"></i> Save Post</button> | |||
<button class="btn btn-default btn-post-add-picture pull-right"> | |||
<i class="icon-camera"></i> Add Picture | |||
</button> | |||
<!-- hidden file input --> | |||
<input type="file" class="control-post-add-picture hide" | |||
style="position: absolute; top: 0; width: 0; height: 0;"> | |||
</div> | |||
</div> |
@@ -0,0 +1,11 @@ | |||
{% if posts %} | |||
{% for post in posts %} | |||
{% include "templates/includes/inline_post.html" %} | |||
{% endfor %} | |||
{% else %} | |||
{% if limit_start %} | |||
<div class="no-posts alert alert-info">No more posts.</div> | |||
{% else %} | |||
<div class="no-posts alert alert-info">Nothing posted yet.</div> | |||
{% endif %} | |||
{% endif %} |
@@ -0,0 +1,9 @@ | |||
<div class="media"> | |||
<div class="pull-left"> | |||
<img class="media-object" src="{{ profile.user_image }}" style="width: 50px; min-height: 1px"/> | |||
</div> | |||
<div class="media-body"> | |||
<div>{{ profile.first_name or "" }} {{ profile.last_name or "" }}</div> | |||
<div class="text-muted"><small>{{ profile.fb_location or profile.fb_hometown or "" }}</small></div> | |||
</div> | |||
</div> |
@@ -0,0 +1,12 @@ | |||
{%- if children -%} | |||
{%- for child in children -%} | |||
<div class="sidebar-item"> | |||
<a href="/{{ child.name|lower }}" class="no-decoration"> | |||
{{ child.page_title }} | |||
{% if not child.public_read %} | |||
(<i class="icon-fixed-width icon-lock"></i>) | |||
{% endif %} | |||
</a> | |||
</div> | |||
{%- endfor -%} | |||
{%- endif -%} |
@@ -0,0 +1,8 @@ | |||
<tr class="sitemap-permission" data-profile="{{ profile.name }}"> | |||
<td> | |||
{% include "templates/includes/profile_display.html" %} | |||
</td> | |||
<td><input type="checkbox" data-perm="read" {% if profile.read %}checked{% endif %}></td> | |||
<td><input type="checkbox" data-perm="write" {% if profile.write %}checked{% endif %}></td> | |||
<td><input type="checkbox" data-perm="admin" {% if profile.admin %}checked{% endif %}></td> | |||
</tr> |
@@ -5,7 +5,7 @@ | |||
<div id="the-carousel" class="carousel slide"> | |||
<!-- Indicators --> | |||
<ol class="carousel-indicators"> | |||
{% for slide in obj.slides %} | |||
{% for slide in slides %} | |||
<li data-target="#the-carousel" data-slide-to="0" | |||
{%- if loop.index==0 %}class="active"{% endif %}></li> | |||
{% endfor %} | |||
@@ -13,9 +13,9 @@ | |||
<!-- Wrapper for slides --> | |||
<div class="carousel-inner"> | |||
{% for slide in obj.slides %} | |||
{% for slide in slides %} | |||
<div class="{% if slide.idx==1 %}active {% endif %}item"> | |||
<img src="{{ slide.image }}" class="slide-image" /> | |||
<img src="{{ slide.image | scrub_relative_url }}" class="slide-image" /> | |||
{% if slide.heading or slide.description %} | |||
<div class="carousel-caption"> | |||
{% if slide.heading %}<h4>{{ slide.heading }}</h4>{% endif %} | |||
@@ -1,13 +1,12 @@ | |||
{% extends base_template %} | |||
{%- block title -%}Not Found{%- endblock -%} | |||
{% set title="Not Found" %} | |||
{%- block header -%} | |||
<h2 class="text-danger"><i class="icon-exclamation-sign"></i> Page missing or moved</h2> | |||
{%- endblock -%} | |||
{% block content %} | |||
<div class="container content panel-container"> | |||
<div class="panel panel-danger"> | |||
<div class="panel-heading"> | |||
<i class="icon-exclamation-sign"></i> Page missing or moved | |||
</div> | |||
<div class="404-content"> | |||
<div class="panel panel-default"> | |||
<div class="panel-body"> | |||
<p>We are very sorry for this, but the page you are looking for is missing | |||
(this could be because of a typo in the address) or moved.</p> | |||
@@ -0,0 +1,12 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import render_blocks | |||
no_sitemap = 1 | |||
def get_context(context): | |||
return render_blocks(context) |
@@ -1,10 +1,17 @@ | |||
{% extends base_template %} | |||
{% block title %} About Us {% endblock %} | |||
{% set title="About Us" %} | |||
{% block header %}<h2>About Us</h2>{% endblock %} | |||
{% block content %} | |||
<div class="container content"> | |||
{{ obj.doc.company_introduction or "<h2>About Us</h2><p>Some Introduction about your company that you would like your website visitor to know. More people than you think will read your About page. People always like to know who the are doing business with. Be authentic and avoid using jargon like 'value added services' etc. Be sure to update your company history and list of key team members in Website > About Us Settings</p>" }} | |||
<div class="about-content"> | |||
{{ obj.doc.company_introduction or """<p>Some Introduction about your company that you would | |||
like your website visitor to know. | |||
More people than you think will read your About page. | |||
People always like to know who the are doing business with. | |||
Be authentic and avoid using jargon like 'value added services' etc. | |||
Be sure to update your company history and | |||
list of key team members in Website > About Us Settings</p>""" }} | |||
{% if obj.doclist.get({"doctype":"Company History"}) %} | |||
<h3>{{ obj.doc.company_history_heading or "Company History" }}</h3> | |||
{% for d in obj.doclist.get({"doctype":"Company History"}) %} | |||
@@ -14,6 +21,7 @@ | |||
</div> | |||
{% endfor %} | |||
{% endif %} | |||
{% if obj.doclist.get({"doctype":"About Us Team Member"}) %} | |||
<h3>{{ obj.doc.team_members_heading or "Team Members" }}</h3> | |||
{% for d in obj.doclist.get({"doctype":"About Us Team Member"}) %} | |||
@@ -31,4 +39,4 @@ | |||
{% endif %} | |||
{{ obj.doc.footer or "" }} | |||
</div> | |||
{% endblock %} | |||
{% endblock %} |
@@ -3,8 +3,12 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import render_blocks | |||
def get_context(): | |||
return { | |||
def get_context(context): | |||
about_context = { | |||
"obj": webnotes.bean("About Us Settings", "About Us Settings").get_controller() | |||
} | |||
} | |||
about_context.update(context) | |||
return render_blocks(about_context) |
@@ -16,7 +16,7 @@ | |||
{% for include in include_css -%} | |||
<link type="text/css" rel="stylesheet" href="{{ include }}"> | |||
{%- endfor -%} | |||
<script type="text/javascript" src="assets/webnotes/js/lib/jquery/jquery.min.js"></script> | |||
<script type="text/javascript" src="/assets/webnotes/js/lib/jquery/jquery.min.js"></script> | |||
<script type="text/javascript"> | |||
window._version_number = "{{ build_version }}"; | |||
// browser support | |||
@@ -3,10 +3,12 @@ | |||
from __future__ import unicode_literals | |||
no_cache = True | |||
no_sitemap = 1 | |||
base_template_path = "templates/pages/app.html" | |||
import webnotes, os | |||
def get_context(): | |||
def get_context(context): | |||
hooks = webnotes.get_hooks() | |||
return { | |||
"build_version": str(os.path.getmtime(os.path.join(webnotes.local.sites_path, "assets", "js", | |||
@@ -1,22 +1,9 @@ | |||
{% extends base_template %} | |||
{% block title %}{{ blog_title or "Blog" }}{% endblock %} | |||
{% block javascript %} | |||
<script> | |||
{% include "templates/includes/blog.js" %} | |||
</script> | |||
{% endblock %} | |||
{% block css %} | |||
<style> | |||
{% include "templates/includes/blog.css" %} | |||
</style> | |||
{% endblock %} | |||
{% set title="Blog" %} | |||
{% block header %}<h2>{{ blog_title or "Blog" }}</h2>{% endblock %} | |||
{% block content %} | |||
<div class="container content"> | |||
<h2 id="blog-title">{{ blog_title }}</h2> | |||
<div class="blog-list-content"> | |||
{% if blog_introduction %} | |||
<p>{{ blog_introduction }}</p> | |||
{% endif %} | |||
@@ -33,5 +20,11 @@ | |||
style="display:none;">More...</button> | |||
</div> | |||
</div> | |||
{% include 'templates/includes/blog_footer.html' %} | |||
{% endblock %} | |||
<script> | |||
{% include "templates/includes/blog.js" %} | |||
</script> | |||
{% endblock %} | |||
{% block footer %}{% include 'templates/includes/blog_footer.html' %}{% endblock %} | |||
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} |
@@ -3,6 +3,9 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import render_blocks | |||
def get_context(): | |||
return webnotes.doc("Blog Settings", "Blog Settings").fields | |||
def get_context(context): | |||
blog_context = webnotes.doc("Blog Settings", "Blog Settings").fields | |||
blog_context.update(context) | |||
return render_blocks(blog_context) |
@@ -1,16 +1,9 @@ | |||
{% extends base_template %} | |||
{% block title %}{{ heading or "Contact Us"}}{% endblock %} | |||
{% block javascript %} | |||
<script> | |||
{% include "templates/includes/contact.js" %} | |||
</script> | |||
{% endblock %} | |||
{% set title="Contact Us" %} | |||
{% block header %}<h2>{{ heading or "Contact Us"}}</h2>{% endblock %} | |||
{% block content %} | |||
<div class="container content"> | |||
<h3>{{ heading or "Contact Us"}}</h3> | |||
<div class="contact-content"> | |||
<div class="row"> | |||
<div class="col-md-8"> | |||
<p id="contact-alert" class="alert alert-warning" | |||
@@ -62,6 +55,9 @@ | |||
</div> | |||
{% endif %} | |||
</div> | |||
{{ introduction }} | |||
{{ introduction or ""}} | |||
</div> | |||
<script> | |||
{% include "templates/includes/contact.js" %} | |||
</script> | |||
{% endblock %} |
@@ -5,22 +5,25 @@ from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.utils import now | |||
from webnotes.webutils import render_blocks | |||
def get_context(): | |||
def get_context(context): | |||
bean = webnotes.bean("Contact Us Settings", "Contact Us Settings") | |||
query_options = filter(None, bean.doc.query_options.replace(",", "\n").split()) if \ | |||
bean.doc.query_options else ["Sales", "Support", "General"] | |||
address = webnotes.bean("Address", bean.doc.address).doc if bean.doc.address else None | |||
return { | |||
contact_context = { | |||
"query_options": query_options, | |||
"address": address, | |||
"heading": bean.doc.heading, | |||
"introduction": bean.doc.introduction | |||
} | |||
contact_context.update(context) | |||
return render_blocks(contact_context) | |||
max_communications_per_hour = 300 | |||
@@ -1,16 +1,13 @@ | |||
{% extends base_template %} | |||
{% block title %}Error{% endblock %} | |||
{% set title="Error" %} | |||
{% block header %} | |||
<h2 class="text-danger"> | |||
<i class="icon-exclamation-sign"></i> Oops, a server error has occured | |||
</h2> | |||
{% endblock %} | |||
{% block content %} | |||
<div class="container content panel-container"> | |||
<div class="panel panel-danger"> | |||
<div class="panel-heading"> | |||
<i class="icon-exclamation-sign"></i> Oops, a server error has occured | |||
</div> | |||
<div class="panel-body"> | |||
<pre>%(error)s</pre> | |||
</div> | |||
</div> | |||
<div class="error-content"> | |||
<pre>{{ error }}</pre> | |||
</div> | |||
{% endblock %} |
@@ -2,5 +2,14 @@ | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import render_blocks | |||
no_cache = True | |||
no_cache = 1 | |||
no_sitemap = 1 | |||
def get_context(context): | |||
error_context = {"error": webnotes.get_traceback()} | |||
error_context.update(context) | |||
return render_blocks(error_context) |
@@ -1,24 +1,7 @@ | |||
{% extends base_template %} | |||
{% block css %} | |||
<style> | |||
@media (min-width: 992px) { | |||
.login-wrapper { | |||
border-right: 1px solid #f2f2f2; | |||
} | |||
} | |||
</style> | |||
{% endblock %} | |||
{% set title=_("Login") %} | |||
{% block title %} Login {% endblock %} | |||
{% block content %} | |||
{% if not top_bar_items %} | |||
<!--<style>body { background-color: #F5EFE6; }</style>--> | |||
{% endif %} | |||
<div class="container content" style="max-width: 800px;"> | |||
<div class="login-content container" style="max-width: 800px;"> | |||
<div class="row" style="margin-top: 70px; margin-bottom: 20px"> | |||
<div class="col-sm-offset-1 col-sm-10"> | |||
<div class="panel panel-default"> | |||
@@ -44,12 +27,17 @@ | |||
<div class="form-group"> | |||
<button type="submit" id="login_btn" | |||
class="btn btn-primary">{{ _("Login") }}</button> | |||
<img src="assets/webnotes/images/ui/button-load.gif" id="login-spinner" | |||
<img src="/assets/webnotes/images/ui/button-load.gif" id="login-spinner" | |||
style="display: none;"> | |||
</div> | |||
<p id="forgot-link"></p> | |||
</div> | |||
<div class="col-sm-6"> | |||
{%- if fb_app_id is defined -%} | |||
<div id="fb-root"></div> | |||
<p><button type="button" class="btn btn-default btn-login"> | |||
Login via Facebook</button></p> | |||
{%- endif -%} | |||
<p id="switch-view"></p> | |||
</div> | |||
</div> | |||
@@ -60,6 +48,4 @@ | |||
<script> | |||
{% include "templates/includes/login.js" %} | |||
</script> | |||
{% endblock %} |
@@ -1,6 +1,5 @@ | |||
import webnotes | |||
from webnotes.webutils import render_blocks | |||
def get_context(): | |||
return { | |||
"title": webnotes._("Login") | |||
} | |||
def get_context(context): | |||
return render_blocks(context) |
@@ -1,15 +1,12 @@ | |||
{% extends base_template %} | |||
{% block title %}{{ title }}{% endblock %} | |||
{% set title=webnotes.local.message_title %} | |||
{% block header %}<h2 class="text-{{ 'success' if success else 'danger'}}">{{ title }}</h2>{% endblock %} | |||
{% block content %} | |||
<div class="container content panel-container"> | |||
<div class="panel panel-{{ 'success' if webnotes.local.message_success else 'danger'}}"> | |||
<div class="panel-heading"> | |||
{{ title }} | |||
</div> | |||
<div class="message-content"> | |||
<div class="panel panel-default"> | |||
<div class="panel-body"> | |||
<p>{{ webnotes.local.message }}</p> | |||
<p>{{ message }}</p> | |||
</div> | |||
</div> | |||
</div> |
@@ -2,5 +2,19 @@ | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import render_blocks | |||
no_cache = True | |||
no_cache = 1 | |||
no_sitemap = 1 | |||
def get_context(context): | |||
message_context = {} | |||
if hasattr(webnotes.local, "message"): | |||
message_context["title"] = webnotes.local.message_title | |||
message_context["message"] = webnotes.local.message | |||
if hasattr(webnotes.local, "message_success"): | |||
message_context["success"] = webnotes.local.message_success | |||
message_context.update(context) | |||
return render_blocks(message_context) |
@@ -3,8 +3,10 @@ | |||
from __future__ import unicode_literals | |||
no_cache = True | |||
no_cache = 1 | |||
no_sitemap = 1 | |||
base_template_path = "templates/pages/print.html" | |||
def get_context(): | |||
def get_context(context): | |||
from webnotes.core.doctype.print_format.print_format import get_args | |||
return get_args() |
@@ -6,9 +6,10 @@ import webnotes | |||
import os, urllib | |||
from webnotes.utils import escape_html, get_request_site_address, now, cstr | |||
no_cache = True | |||
no_cache = 1 | |||
base_template_path = "templates/pages/rss.xml" | |||
def get_context(): | |||
def get_context(context): | |||
"""generate rss feed""" | |||
host = get_request_site_address() | |||
@@ -19,7 +20,8 @@ def get_context(): | |||
order by published_on desc limit 20""", as_dict=1) | |||
for blog in blog_list: | |||
blog.link = cstr(urllib.quote((host + '/' + blog.name + '.html').encode("utf-8"))) | |||
blog_page = cstr(urllib.quote(blog.name.encode("utf-8"))) + ".html" | |||
blog.link = urllib.basejoin(host, blog_page) | |||
blog.content = escape_html(blog.content or "") | |||
if blog_list: | |||
@@ -10,8 +10,9 @@ from webnotes.utils import get_request_site_address | |||
no_cache = 1 | |||
no_sitemap = 1 | |||
base_template_path = "templates/pages/sitemap.xml" | |||
def get_context(): | |||
def get_context(context): | |||
"""generate the sitemap XML""" | |||
host = get_request_site_address() | |||
links = [] | |||
@@ -54,7 +54,7 @@ div.outer { | |||
{% else %} | |||
{% if doc.background_color.lower() == doc.page_background.lower() %} | |||
.web-footer { | |||
border-top: 1px solid #{{ get_hex_shade(doc.page_background, 15) }}; | |||
border-top: 1px solid #{{ doc.page_background | get_hex_shade(15) }}; | |||
padding-top: 10px; | |||
} | |||
{% endif %} | |||
@@ -62,7 +62,7 @@ div.outer { | |||
.web-footer, .web-footer a { | |||
font-size: 90%; | |||
color: #{{ get_hex_shade(doc.background_color, 70) }}; | |||
color: #{{ doc.background_color | get_hex_shade(70) }}; | |||
} | |||
/* Bootstrap Navbar */ | |||
@@ -75,7 +75,7 @@ div.outer { | |||
background-repeat: repeat-x; | |||
background-image: none; | |||
border-bottom: 1px solid {% if doc.top_bar_background.lower() == doc.page_background.lower() -%} | |||
#{{ get_hex_shade(doc.page_background, 15) }}; | |||
#{{ doc.page_background | get_hex_shade(15) }}; | |||
{%- else -%} | |||
transparent; | |||
{%- endif %} | |||
@@ -185,7 +185,7 @@ div.outer { | |||
} | |||
.breadcrumb { | |||
background-color: #{{ get_hex_shade(doc.page_background, 5) }}; | |||
background-color: #{{ doc.page_background | get_hex_shade(5) }}; | |||
} | |||
.breadcrumb > li { | |||
@@ -195,41 +195,41 @@ div.outer { | |||
.table-striped tbody > tr:nth-child(odd) > td, | |||
.table-striped tbody > tr:nth-child(odd) > th { | |||
background-color: #{{ get_hex_shade(doc.page_background, 5) }}; | |||
background-color: #{{ doc.page_background | get_hex_shade(5) }}; | |||
} | |||
.table-hover tbody tr:hover td, | |||
.table-hover tbody tr:hover th { | |||
background-color: #{{ get_hex_shade(doc.page_background, 10) }}; | |||
background-color: #{{ doc.page_background | get_hex_shade(10) }}; | |||
} | |||
.table-bordered { | |||
border: 1px solid #{{ get_hex_shade(doc.page_background, 15) }}; | |||
border: 1px solid #{{ doc.page_background | get_hex_shade(15) }}; | |||
} | |||
.table th, | |||
.table td { | |||
border-top: 1px solid #{{ get_hex_shade(doc.page_background, 15) }}; | |||
border-top: 1px solid #{{ doc.page_background | get_hex_shade(15) }}; | |||
} | |||
.table-bordered th, | |||
.table-bordered td { | |||
border-left: 1px solid #{{ get_hex_shade(doc.page_background, 15) }}; | |||
border-left: 1px solid #{{ doc.page_background | get_hex_shade(15) }}; | |||
} | |||
.hero-unit { | |||
background-color: #{{ get_hex_shade(doc.page_background, 15) }}; | |||
background-color: #{{ doc.page_background | get_hex_shade(15) }}; | |||
} | |||
pre, code { | |||
background-color: #{{ get_hex_shade(doc.page_background, 5) }}; | |||
background-color: #{{ doc.page_background | get_hex_shade(5) }}; | |||
} | |||
hr { | |||
border-top: 1px solid #{{ get_hex_shade(doc.page_background, 15) }}; | |||
border-bottom: 1px solid #{{ get_hex_shade(doc.page_background, 5) }}; | |||
border-top: 1px solid #{{ doc.page_background | get_hex_shade(15) }}; | |||
border-bottom: 1px solid #{{ doc.page_background | get_hex_shade(5) }}; | |||
} | |||
{% if doc.add_css -%} | |||
@@ -3,19 +3,16 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
no_sitemap = True | |||
def get_context(): | |||
no_sitemap = 1 | |||
base_template_path = "templates/pages/style_settings.css" | |||
def get_context(context): | |||
"""returns web style""" | |||
from webnotes.webutils import get_hex_shade | |||
doc = webnotes.doc("Style Settings", "Style Settings") | |||
prepare(doc) | |||
return { | |||
"doc": doc, | |||
"get_hex_shade": get_hex_shade | |||
} | |||
return { "doc": doc.fields } | |||
def prepare(doc): | |||
from webnotes.utils import cint, cstr | |||
@@ -1,4 +1,4 @@ | |||
{% extends base_template %} | |||
{% block title %} Reset Password {% endblock %} | |||
{% block content %} | |||
<div class="container"> | |||
@@ -2,5 +2,9 @@ | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
from webnotes.webutils import render_blocks | |||
no_sitemap = True | |||
no_sitemap = 1 | |||
def get_context(context): | |||
return render_blocks(context) |
@@ -4,9 +4,10 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
no_sitemap = True | |||
no_sitemap = 1 | |||
base_template_path = "templates/pages/website_script.js" | |||
def get_context(): | |||
def get_context(context): | |||
return { | |||
"javascript": webnotes.conn.get_value('Website Script', None, 'javascript'), | |||
"google_analytics_id": webnotes.conn.get_value("Website Settings", "Website Settings", "google_analytics_id") |
@@ -1,18 +1,19 @@ | |||
{% extends base_template %} | |||
{% block title %} Blog Writers {% endblock %} | |||
{% set title="Blog Writers" %} | |||
{% block header %}<h2>Blog Writers</h2>{% endblock %} | |||
{% block content %} | |||
<div class="container content"> | |||
<h2 id="blog-title">Blog Writers</h2> | |||
<div class="writers-content"> | |||
{% if writers_introduction %} | |||
<p>{{ writers_introduction }}</p> | |||
{% endif %} | |||
<hr> | |||
{% for blogger_info in bloggers %} | |||
{% include "templates/includes/blogger.html" %} | |||
{% if not loop.last %}<hr>{% endif %} | |||
{% endfor %} | |||
</div> | |||
{% include 'templates/includes/blog_footer.html' %} | |||
{% endblock %} | |||
{% endblock %} | |||
{% block footer %}{% include "templates/includes/blog_footer.html" %}{% endblock %} | |||
{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} |
@@ -3,13 +3,14 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import render_blocks | |||
def get_context(): | |||
def get_context(context): | |||
bloggers = webnotes.conn.sql("""select * from `tabBlogger` | |||
where ifnull(posts,0) > 0 and ifnull(disabled,0)=0 | |||
order by posts desc""", as_dict=1) | |||
args = { | |||
writers_context = { | |||
"bloggers": bloggers, | |||
"texts": { | |||
"all_posts_by": "All posts by" | |||
@@ -17,5 +18,7 @@ def get_context(): | |||
"categories": webnotes.conn.sql_list("select name from `tabBlog Category` order by name") | |||
} | |||
args.update(webnotes.doc("Blog Settings", "Blog Settings").fields) | |||
return args | |||
writers_context.update(webnotes.doc("Blog Settings", "Blog Settings").fields) | |||
writers_context.update(context) | |||
return render_blocks(writers_context) |
@@ -0,0 +1,19 @@ | |||
{% include "templates/includes/post_editor.html" %} | |||
<script type="text/javascript" src="/assets/js/canvasResize.min.js"></script> | |||
<script> | |||
$(function() { | |||
website.bind_add_post(); | |||
{%- if view.name == "edit" -%} | |||
website.bind_save_post(); | |||
{% if post -%} website.post = "{{ post.name }}"; {%- endif %} | |||
{%- endif -%} | |||
{%- if group.group_type == "Events" -%} | |||
website.setup_event_editor(); | |||
{%- elif group.group_type == "Tasks" -%} | |||
website.setup_tasks_editor(); | |||
{%- endif -%} | |||
}); | |||
</script> |
@@ -0,0 +1,29 @@ | |||
<div class="small text-muted post-list-help"></div> | |||
<div class="post-list"> | |||
{{ post_list_html }} | |||
</div> | |||
<div class="text-center"> | |||
<button class="btn btn-default btn-more hide">More</button> | |||
</div> | |||
<script> | |||
$(function() { | |||
if($(".post").length===20) { | |||
wn.setup_pagination($(".btn-more"), { | |||
args: { | |||
cmd: "webnotes.templates.website_group.events.get_post_list_html", | |||
limit_start: $(".post").length, | |||
limit_length: 20, | |||
group: website.group, | |||
view: website.view | |||
}, | |||
$wrapper: $(".post-list") | |||
}); | |||
} | |||
website.toggle_edit(); | |||
website.setup_upvote(); | |||
website.toggle_upvote(); | |||
website.format_event_timestamps(); | |||
}); | |||
</script> |
@@ -0,0 +1,125 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.utils import now_datetime, get_datetime_str | |||
from webnotes.webutils import get_access | |||
from webnotes.templates.website_group.settings import get_settings_context | |||
from webnotes.templates.website_group.post import get_post_context | |||
def get_views(): | |||
return views | |||
def get_context(group_context): | |||
events_context = {} | |||
if group_context.view.name in ("upcoming", "past"): | |||
events_context["post_list_html"] = get_post_list_html(group_context["group"]["name"], group_context["view"]) | |||
elif group_context.view.name == "edit": | |||
events_context["session_user"] = webnotes.session.user | |||
events_context["post"] = webnotes.doc("Post", webnotes.form_dict.name).fields | |||
elif group_context.view.name == "settings": | |||
events_context.update(get_settings_context(group_context)) | |||
elif group_context.view.name == "post": | |||
events_context.update(get_post_context(group_context)) | |||
return events_context | |||
@webnotes.whitelist(allow_guest=True) | |||
def get_post_list_html(group, view, limit_start=0, limit_length=20): | |||
access = get_access(group) | |||
if isinstance(view, basestring): | |||
view = get_views()[view] | |||
view = webnotes._dict(view) | |||
# verify permission for paging | |||
if webnotes.local.form_dict.cmd == "get_post_list_html": | |||
if not access.get("read"): | |||
return webnotes.PermissionError | |||
if view.name=="upcoming": | |||
condition = "and p.event_datetime >= %s" | |||
order_by = "p.event_datetime asc" | |||
else: | |||
condition = "and p.event_datetime < %s" | |||
order_by = "p.event_datetime desc" | |||
# should show based on time upto precision of hour | |||
# because the current hour should also be in upcoming | |||
now = now_datetime().replace(minute=0, second=0, microsecond=0) | |||
posts = webnotes.conn.sql("""select p.*, pr.user_image, pr.first_name, pr.last_name, | |||
(select count(pc.name) from `tabPost` pc where pc.parent_post=p.name) as post_reply_count | |||
from `tabPost` p, `tabProfile` pr | |||
where p.website_group = %s and pr.name = p.owner and ifnull(p.parent_post, '')='' | |||
and p.is_event=1 {condition} | |||
order by {order_by} limit %s, %s""".format(condition=condition, order_by=order_by), | |||
(group, now, int(limit_start), int(limit_length)), as_dict=True) | |||
context = {"posts": posts, "limit_start": limit_start, "view": view} | |||
return webnotes.get_template("templates/includes/post_list.html").render(context) | |||
views = { | |||
"upcoming": { | |||
"name": "upcoming", | |||
"template_path": "templates/website_group/events.html", | |||
"url": "/{group}", | |||
"label": "Upcoming", | |||
"icon": "icon-calendar", | |||
"default": True, | |||
"idx": 1 | |||
}, | |||
"past": { | |||
"name": "past", | |||
"template_path": "templates/website_group/events.html", | |||
"url": "/{group}?view=past", | |||
"label": "Past", | |||
"icon": "icon-time", | |||
"idx": 2 | |||
}, | |||
"post": { | |||
"name": "post", | |||
"template_path": "templates/website_group/post.html", | |||
"url": "/{group}?view=post&name={post}", | |||
"label": "Post", | |||
"icon": "icon-comments", | |||
"hidden": True, | |||
"no_cache": True, | |||
"idx": 3 | |||
}, | |||
"edit": { | |||
"name": "edit", | |||
"template_path": "templates/website_group/edit_post.html", | |||
"url": "/{group}?view=edit&name={post}", | |||
"label": "Edit Post", | |||
"icon": "icon-pencil", | |||
"hidden": True, | |||
"no_cache": True, | |||
"idx": 4 | |||
}, | |||
"add": { | |||
"name": "add", | |||
"template_path": "templates/website_group/edit_post.html", | |||
"url": "/{group}?view=add", | |||
"label": "Add Post", | |||
"icon": "icon-plus", | |||
"hidden": True, | |||
"idx": 5 | |||
}, | |||
"settings": { | |||
"name": "settings", | |||
"template_path": "templates/website_group/settings.html", | |||
"url": "/{group}?view=settings", | |||
"label": "Settings", | |||
"icon": "icon-cog", | |||
"hidden": True, | |||
"idx": 6 | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
<div class="small text-muted post-list-help"></div> | |||
<div class="post-list"> | |||
{{ post_list_html }} | |||
</div> | |||
<div class="text-center"> | |||
<button class="btn btn-default btn-more hide">More</button> | |||
</div> | |||
<script> | |||
$(function() { | |||
if($(".post").length===20) { | |||
wn.setup_pagination($(".btn-more"), { | |||
args: { | |||
cmd: "webnotes.templates.website_group.forum.get_post_list_html", | |||
limit_start: $(".post").length, | |||
limit_length: 20, | |||
group: website.group, | |||
view: website.view | |||
}, | |||
$wrapper: $(".post-list") | |||
}); | |||
} | |||
website.toggle_edit(true); | |||
website.setup_upvote(); | |||
website.toggle_upvote(); | |||
}); | |||
</script> |
@@ -0,0 +1,123 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.utils import now_datetime, get_datetime_str | |||
from webnotes.webutils import get_access | |||
from webnotes.templates.website_group.settings import get_settings_context | |||
from webnotes.templates.website_group.post import get_post_context | |||
def get_views(): | |||
return views | |||
def get_context(group_context): | |||
forum_context = {} | |||
if group_context.view.name in ("popular", "feed"): | |||
forum_context["post_list_html"] = get_post_list_html(group_context["group"]["name"], group_context["view"]) | |||
elif group_context.view.name == "edit": | |||
forum_context["session_user"] = webnotes.session.user | |||
forum_context["post"] = webnotes.doc("Post", webnotes.form_dict.name).fields | |||
elif group_context.view.name == "settings": | |||
forum_context.update(get_settings_context(group_context)) | |||
elif group_context.view.name == "post": | |||
forum_context.update(get_post_context(group_context)) | |||
return forum_context | |||
@webnotes.whitelist(allow_guest=True) | |||
def get_post_list_html(group, view, limit_start=0, limit_length=20): | |||
access = get_access(group) | |||
if isinstance(view, basestring): | |||
view = get_views()[view] | |||
view = webnotes._dict(view) | |||
# verify permission for paging | |||
if webnotes.local.form_dict.cmd == "get_post_list_html": | |||
if not access.get("read"): | |||
return webnotes.PermissionError | |||
if view.name == "feed": | |||
order_by = "p.creation desc" | |||
else: | |||
now = get_datetime_str(now_datetime()) | |||
order_by = """(p.upvotes + post_reply_count - (timestampdiff(hour, p.creation, \"{}\") / 2)) desc, | |||
p.creation desc""".format(now) | |||
posts = webnotes.conn.sql("""select p.*, pr.user_image, pr.first_name, pr.last_name, | |||
(select count(pc.name) from `tabPost` pc where pc.parent_post=p.name) as post_reply_count | |||
from `tabPost` p, `tabProfile` pr | |||
where p.website_group = %s and pr.name = p.owner and ifnull(p.parent_post, '')='' | |||
order by {order_by} limit %s, %s""".format(order_by=order_by), | |||
(group, int(limit_start), int(limit_length)), as_dict=True) | |||
context = {"posts": posts, "limit_start": limit_start, "view": view} | |||
return webnotes.get_template("templates/includes/post_list.html").render(context) | |||
views = { | |||
"popular": { | |||
"name": "popular", | |||
"template_path": "templates/website_group/forum.html", | |||
"url": "/{group}", | |||
"label": "Popular", | |||
"icon": "icon-heart", | |||
"default": True, | |||
"upvote": True, | |||
"idx": 1 | |||
}, | |||
"feed": { | |||
"name": "feed", | |||
"template_path": "templates/website_group/forum.html", | |||
"url": "/{group}?view=feed", | |||
"label": "Feed", | |||
"icon": "icon-rss", | |||
"upvote": True, | |||
"idx": 2 | |||
}, | |||
"post": { | |||
"name": "post", | |||
"template_path": "templates/website_group/post.html", | |||
"url": "/{group}?view=post&name={post}", | |||
"label": "Post", | |||
"icon": "icon-comments", | |||
"upvote": True, | |||
"hidden": True, | |||
"no_cache": True, | |||
"idx": 3 | |||
}, | |||
"edit": { | |||
"name": "edit", | |||
"template_path": "templates/website_group/edit_post.html", | |||
"url": "/{group}?view=edit&name={post}", | |||
"label": "Edit Post", | |||
"icon": "icon-pencil", | |||
"hidden": True, | |||
"no_cache": True, | |||
"idx": 4 | |||
}, | |||
"add": { | |||
"name": "add", | |||
"template_path": "templates/website_group/edit_post.html", | |||
"url": "/{group}?view=add", | |||
"label": "Add Post", | |||
"icon": "icon-plus", | |||
"hidden": True, | |||
"idx": 5 | |||
}, | |||
"settings": { | |||
"name": "settings", | |||
"template_path": "templates/website_group/settings.html", | |||
"url": "/{group}?view=settings", | |||
"label": "Settings", | |||
"icon": "icon-cog", | |||
"hidden": True, | |||
"idx": 6 | |||
} | |||
} |
@@ -0,0 +1,34 @@ | |||
<div class="small text-muted post-list-help"></div> | |||
<div class="parent-post">{{ parent_post_html }}</div> | |||
<div class="text-center"> | |||
<button type="button" style="margin-bottom: 15px" | |||
class="btn btn-default btn-earlier-replies hide"> | |||
<span class="btn-earlier-label">Show</span> Earlier Replies</button> | |||
</div> | |||
<div class="post-list"> | |||
{{ post_list_html }} | |||
</div> | |||
<div style="margin-top: 15px"> | |||
{% include "templates/includes/post_editor.html" %} | |||
</div> | |||
<script type="text/javascript" src="/assets/js/canvasResize.min.js"></script> | |||
<script> | |||
$(function() { | |||
website.toggle_edit(true); | |||
website.setup_upvote(); | |||
website.toggle_upvote(); | |||
website.bind_add_post(); | |||
// show/hide earlier replies | |||
website.toggle_earlier_replies(); | |||
{%- if group.group_type == "Events" -%} | |||
website.format_event_timestamps(); | |||
{%- endif -%} | |||
website.toggle_post_editor(); | |||
$('[data-view="post"]').removeClass("hide"); | |||
}); | |||
</script> |
@@ -0,0 +1,52 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.utils import get_fullname | |||
def get_post_context(group_context): | |||
post = webnotes.doc("Post", webnotes.form_dict.name) | |||
if post.parent_post: | |||
raise webnotes.PermissionError | |||
def _get_post_context(): | |||
fullname = get_fullname(post.owner) | |||
return { | |||
"title": "{} by {}".format(post.title, fullname), | |||
# "group_title": group_context.get("unit_title") + " by {}".format(fullname), | |||
"parent_post_html": get_parent_post_html(post, group_context.get("view")), | |||
"post_list_html": get_child_posts_html(post, group_context.get("view")), | |||
"parent_post": post.name | |||
} | |||
cache_key = "website_group_post:".format(post.name) | |||
return webnotes.cache().get_value(cache_key, lambda: _get_post_context()) | |||
def get_parent_post_html(post, view): | |||
profile = webnotes.bean("Profile", post.owner).doc | |||
for fieldname in ("first_name", "last_name", "user_image", "fb_hometown", "fb_location"): | |||
post.fields[fieldname] = profile.fields[fieldname] | |||
return webnotes.get_template("templates/includes/inline_post.html")\ | |||
.render({"post": post.fields, "view": view}) | |||
def get_child_posts_html(post, view): | |||
posts = webnotes.conn.sql("""select p.*, pr.user_image, pr.first_name, pr.last_name | |||
from tabPost p, tabProfile pr | |||
where p.parent_post=%s and pr.name = p.owner | |||
order by p.creation asc""", (post.name,), as_dict=True) | |||
return webnotes.get_template("templates/includes/post_list.html")\ | |||
.render({ | |||
"posts": posts, | |||
"parent_post": post.name, | |||
"view": view | |||
}) | |||
def clear_post_cache(post=None): | |||
cache = webnotes.cache() | |||
posts = [post] if post else webnotes.conn.sql_list("select name from `tabPost`") | |||
for post in posts: | |||
cache.delete_value("website_group_post:{}".format(post)) |
@@ -0,0 +1,77 @@ | |||
<div class="permission-editor-area"> | |||
<div class="well permission-editor"> | |||
<h4>1. Edit Description</h4> | |||
<div class="row"> | |||
<div class="col-xs-12"> | |||
<p> | |||
<textarea class="form-control control-description" | |||
style="height: 100px;">{{ group.group_description or "" }}</textarea> | |||
</p> | |||
<div> | |||
<button class="btn btn-default btn-update-description" | |||
onclick="website.update_group_description()">Update</button> | |||
</div> | |||
</div> | |||
</div> | |||
<hr> | |||
<h4>2. Add Sub Groups</h4> | |||
<div class="row"> | |||
<div class="col-xs-12"> | |||
<div class="form-group"> | |||
<input class="form-control control-add-group" placeholder="New Group Name" /> | |||
<p class="help-block small">Only letters, numbers and spaces</p> | |||
</div> | |||
<div class="form-group"> | |||
<label>Group Type</label> | |||
<select class="form-control control-add-group-type" data-fieldname="group_type"> | |||
{%- for group_type in ("Forum", "Tasks", "Events") -%} | |||
<option value="{{ group_type }}">{{ group_type }}</option> | |||
{%- endfor -%} | |||
</select> | |||
</div> | |||
<div class="checkbox" style="position: static;"> | |||
<label> | |||
<input type="checkbox" class="control-add-group-public_read" | |||
{{ "checked" if public_read else "disabled" }}> <span>Allow all users to read</span> | |||
</label> | |||
<p class="help-block small">Private if unchecked, only users with explicit read access will be allowed to read</p> | |||
</div> | |||
<div class="checkbox" style="position: static;"> | |||
<label> | |||
<input type="checkbox" class="control-add-group-public_write" | |||
{{ "checked" if public_write else "disabled" }}> <span>Allow all users to write</span> | |||
<p class="help-block small">Public Forum</p> | |||
</label> | |||
</div> | |||
<div> | |||
<button class="btn btn-default btn-add-group"><i class="icon-plus"></i> Add</button> | |||
</div> | |||
</div> | |||
</div> | |||
<hr> | |||
<h4>3. Manage Users</h4> | |||
<input class="form-control add-user-control" type="text" placeholder="Select User" /> | |||
<br> | |||
<table class="table table-bordered"> | |||
<thead> | |||
<tr> | |||
<th style="width: 55%">User</th> | |||
<th style="width: 15%">Read</th> | |||
<th style="width: 15%">Write</th> | |||
<th style="width: 15%">Admin</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
{% for profile in profiles %} | |||
{% include "templates/includes/sitemap_permission.html" %} | |||
{% endfor %} | |||
</tbody> | |||
</table> | |||
</div> | |||
</div> | |||
<script> | |||
$(function() { | |||
website.setup_settings(); | |||
}) | |||
</script> |
@@ -0,0 +1,105 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import get_access | |||
from webnotes.website.doctype.website_sitemap_permission.website_sitemap_permission import clear_permissions | |||
from webnotes.utils.email_lib.bulk import send | |||
def get_settings_context(group_context): | |||
if not get_access(group_context.group.name).get("admin"): | |||
raise webnotes.PermissionError | |||
return { | |||
"profiles": webnotes.conn.sql("""select p.*, wsp.`read`, wsp.`write`, wsp.`admin` | |||
from `tabProfile` p, `tabWebsite Sitemap Permission` wsp | |||
where wsp.website_sitemap=%s and wsp.profile=p.name""", (group_context.group.name,), as_dict=True) | |||
} | |||
@webnotes.whitelist() | |||
def suggest_user(term, group): | |||
profiles = webnotes.conn.sql("""select pr.name, pr.first_name, pr.last_name, | |||
pr.user_image, pr.fb_location, pr.fb_hometown | |||
from `tabProfile` pr | |||
where (pr.first_name like %(term)s or pr.last_name like %(term)s) | |||
and pr.user_image is not null and pr.enabled=1 | |||
and not exists(select wsp.name from `tabWebsite Sitemap Permission` wsp | |||
where wsp.website_sitemap=%(group)s and wsp.profile=pr.name)""", | |||
{"term": "%{}%".format(term), "group": group}, as_dict=True) | |||
template = webnotes.get_template("templates/includes/profile_display.html") | |||
return [{ | |||
"value": "{} {}".format(pr.first_name, pr.last_name), | |||
"profile_html": template.render({"profile": pr}), | |||
"profile": pr.name | |||
} for pr in profiles] | |||
@webnotes.whitelist() | |||
def add_sitemap_permission(sitemap_page, profile): | |||
if not get_access(sitemap_page).get("admin"): | |||
raise webnotes.PermissionError | |||
permission = webnotes.bean({ | |||
"doctype": "Website Sitemap Permission", | |||
"website_sitemap": sitemap_page, | |||
"profile": profile, | |||
"read": 1 | |||
}) | |||
permission.insert(ignore_permissions=True) | |||
profile = permission.doc.fields | |||
profile.update(webnotes.conn.get_value("Profile", profile.profile, | |||
["name", "first_name", "last_name", "user_image", "fb_location", "fb_hometown"], as_dict=True)) | |||
return webnotes.get_template("templates/includes/sitemap_permission.html").render({ | |||
"profile": profile | |||
}) | |||
@webnotes.whitelist() | |||
def update_permission(sitemap_page, profile, perm, value): | |||
if not get_access(sitemap_page).get("admin"): | |||
raise webnotes.PermissionError | |||
permission = webnotes.bean("Website Sitemap Permission", {"website_sitemap": sitemap_page, "profile": profile}) | |||
permission.doc.fields[perm] = int(value) | |||
permission.save(ignore_permissions=True) | |||
# send email | |||
if perm=="admin" and int(value): | |||
group_title = webnotes.conn.get_value("Website Sitemap", sitemap_page, "page_title") | |||
subject = "You have been made Administrator of Group " + group_title | |||
send(recipients=[profile], | |||
subject= subject, add_unsubscribe_link=False, | |||
message="""<h3>Group Notification<h3>\ | |||
<p>%s</p>\ | |||
<p style="color: #888">This is just for your information.</p>""" % subject) | |||
@webnotes.whitelist() | |||
def update_description(group, description): | |||
if not get_access(group).get("admin"): | |||
raise webnotes.PermissionError | |||
group = webnotes.bean("Website Group", group) | |||
group.doc.group_description = description | |||
group.save(ignore_permissions=True) | |||
@webnotes.whitelist() | |||
def add_website_group(group, new_group, public_read, public_write, group_type="Forum"): | |||
if not get_access(group).get("admin"): | |||
raise webnotes.PermissionError | |||
parent_website_sitemap = webnotes.conn.get_value("Website Sitemap", | |||
{"ref_doctype": "Website Group", "docname": group}) | |||
webnotes.bean({ | |||
"doctype": "Website Group", | |||
"group_name": group + "-" + new_group, | |||
"group_title": new_group, | |||
"parent_website_sitemap": parent_website_sitemap, | |||
"group_type": group_type, | |||
"public_read": int(public_read), | |||
"public_write": int(public_write) | |||
}).insert(ignore_permissions=True) |
@@ -0,0 +1,32 @@ | |||
<div class="small text-muted post-list-help"></div> | |||
<div class="post-list"> | |||
{{ post_list_html }} | |||
</div> | |||
<div class="text-center"> | |||
<button class="btn btn-default btn-more hide">More</button> | |||
</div> | |||
<script> | |||
$(function() { | |||
if($(".post").length===20) { | |||
wn.setup_pagination($(".btn-more"), { | |||
args: { | |||
cmd: "webnotes.templates.website_group.tasks.get_post_list_html", | |||
limit_start: $(".post").length, | |||
limit_length: 20, | |||
group: website.group, | |||
view: website.view, | |||
status: "Closed" ? view=="closed" : undefined | |||
}, | |||
$wrapper: $(".post-list") | |||
}); | |||
} | |||
{%- if view.name == "open" -%} | |||
website.setup_upvote(); | |||
website.toggle_upvote(); | |||
{%- endif -%} | |||
website.toggle_edit(); | |||
}); | |||
</script> |
@@ -0,0 +1,126 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.utils import now_datetime, get_datetime_str | |||
from webnotes.webutils import get_access | |||
from webnotes.templates.website_group.settings import get_settings_context | |||
from webnotes.templates.website_group.post import get_post_context | |||
def get_views(): | |||
return views | |||
def get_context(group_context): | |||
tasks_context = {} | |||
if group_context.view.name in ("open", "closed"): | |||
tasks_context["post_list_html"] = get_post_list_html(group_context["group"]["name"], group_context["view"]) | |||
elif group_context.view.name == "edit": | |||
post = webnotes.doc("Post", webnotes.form_dict.name).fields | |||
tasks_context["session_user"] = webnotes.session.user | |||
tasks_context["post"] = post | |||
if post.assigned_to: | |||
tasks_context["profile"] = webnotes.doc("Profile", post.assigned_to) | |||
elif group_context.view.name == "settings": | |||
tasks_context.update(get_settings_context(group_context)) | |||
elif group_context.view.name == "post": | |||
tasks_context.update(get_post_context(group_context)) | |||
return tasks_context | |||
@webnotes.whitelist(allow_guest=True) | |||
def get_post_list_html(group, view, limit_start=0, limit_length=20, status="Open"): | |||
access = get_access(group) | |||
if isinstance(view, basestring): | |||
view = get_views()[view] | |||
view = webnotes._dict(view) | |||
# verify permission for paging | |||
if webnotes.local.form_dict.cmd == "get_post_list_html": | |||
if not access.get("read"): | |||
return webnotes.PermissionError | |||
if view.name=="open": | |||
now = get_datetime_str(now_datetime()) | |||
order_by = "(p.upvotes + post_reply_count - (timestampdiff(hour, p.creation, \"{}\") / 2)) desc, p.creation desc".format(now) | |||
else: | |||
status = "Closed" | |||
order_by = "p.creation desc" | |||
posts = webnotes.conn.sql("""select p.*, pr.user_image, pr.first_name, pr.last_name, | |||
(select count(pc.name) from `tabPost` pc where pc.parent_post=p.name) as post_reply_count | |||
from `tabPost` p, `tabProfile` pr | |||
where p.website_group = %s and pr.name = p.owner and ifnull(p.parent_post, '')='' | |||
and p.is_task=1 and p.status=%s | |||
order by {order_by} limit %s, %s""".format(order_by=order_by), | |||
(group, status, int(limit_start), int(limit_length)), as_dict=True) | |||
context = {"posts": posts, "limit_start": limit_start, "view": view} | |||
return webnotes.get_template("templates/includes/post_list.html").render(context) | |||
views = { | |||
"open": { | |||
"name": "open", | |||
"template_path": "templates/website_group/tasks.html", | |||
"url": "/{group}", | |||
"label": "Open", | |||
"icon": "icon-inbox", | |||
"default": True, | |||
"upvote": True, | |||
"idx": 1 | |||
}, | |||
"closed": { | |||
"name": "closed", | |||
"template_path": "templates/website_group/tasks.html", | |||
"url": "/{group}?view=closed", | |||
"label": "Closed", | |||
"icon": "icon-smile", | |||
"idx": 2 | |||
}, | |||
"post": { | |||
"name": "post", | |||
"template_path": "templates/website_group/post.html", | |||
"url": "/{group}?view=post&name={post}", | |||
"label": "Post", | |||
"icon": "icon-comments", | |||
"hidden": True, | |||
"no_cache": True, | |||
"upvote": True, | |||
"idx": 3 | |||
}, | |||
"edit": { | |||
"name": "edit", | |||
"template_path": "templates/website_group/edit_post.html", | |||
"url": "/{group}?view=edit&name={post}", | |||
"label": "Edit Post", | |||
"icon": "icon-pencil", | |||
"hidden": True, | |||
"no_cache": True, | |||
"idx": 4 | |||
}, | |||
"add": { | |||
"name": "add", | |||
"template_path": "templates/website_group/edit_post.html", | |||
"url": "/{group}?view=add", | |||
"label": "Add Post", | |||
"icon": "icon-plus", | |||
"hidden": True, | |||
"idx": 5 | |||
}, | |||
"settings": { | |||
"name": "settings", | |||
"template_path": "templates/website_group/settings.html", | |||
"url": "/{group}?view=settings", | |||
"label": "Settings", | |||
"icon": "icon-cog", | |||
"hidden": True, | |||
"idx": 6 | |||
} | |||
} |
@@ -841,6 +841,11 @@ def get_url_to_form(doctype, name, base_url=None, label=None): | |||
if not label: label = name | |||
return """<a href="%(base_url)s/app.html#!Form/%(doctype)s/%(name)s">%(label)s</a>""" % locals() | |||
def scrub_relative_url(url): | |||
if not url or url.startswith("http"): | |||
return url | |||
return "/" + url | |||
def encode_dict(d, encoding="utf-8"): | |||
for key in d: | |||
@@ -3,6 +3,11 @@ | |||
import webnotes | |||
def before_install(): | |||
webnotes.reload_doc("core", "doctype", "docfield") | |||
webnotes.reload_doc("core", "doctype", "docperm") | |||
webnotes.reload_doc("core", "doctype", "doctype") | |||
def after_install(): | |||
# reset installed apps for re-install | |||
webnotes.conn.set_global("installed_apps", '["webnotes"]') | |||
@@ -21,7 +26,10 @@ def after_install(): | |||
] | |||
for d in install_docs: | |||
webnotes.bean(d).insert() | |||
try: | |||
webnotes.bean(d).insert() | |||
except NameError: | |||
pass | |||
# all roles to admin | |||
webnotes.bean("Profile", "Administrator").get_controller().add_roles(*webnotes.conn.sql_list(""" | |||
@@ -1,3 +1,9 @@ | |||
@media (min-width: 768px) { | |||
.login-wrapper { | |||
border-right: 1px solid #f2f2f2; | |||
} | |||
} | |||
h1, h2, h3, h4, h5 { | |||
font-weight: bold; | |||
} | |||
@@ -42,8 +48,7 @@ img { | |||
} | |||
.web-footer { | |||
margin-top: 10px; | |||
padding-bottom: 20px; | |||
padding: 20px 0px; | |||
} | |||
.avatar { | |||
@@ -152,12 +157,14 @@ img { | |||
.navbar { | |||
box-shadow: none; | |||
border-radius: 0px; | |||
margin-bottom: 7px; | |||
margin-bottom: 0px; | |||
} | |||
.navbar-brand { | |||
padding-right: 30px; | |||
max-width: 80%; | |||
min-height: 20px; | |||
height: auto; | |||
} | |||
@media (min-width: 768px) { | |||
@@ -204,4 +211,210 @@ fieldset { | |||
.slide-image { | |||
width: 100%; | |||
} | |||
} | |||
.page-header { | |||
margin: 0px; | |||
padding: 5px 0px; | |||
} | |||
.page-container { | |||
margin-top: 15px; | |||
} | |||
.page-header h1, | |||
.page-header h2, | |||
.page-header h3 { | |||
margin: 5px auto; | |||
} | |||
.page-header .lead { | |||
margin-bottom: 5px; | |||
} | |||
.sidebar-item { | |||
margin: 15px auto; | |||
color: #999; | |||
font-size: 90%; | |||
} | |||
.sidebar-item a:hover { | |||
color: #333; | |||
border-bottom: 2px solid #999; | |||
} | |||
html, | |||
body { | |||
height: 100%; | |||
/* The html and body elements cannot have any padding or margin. */ | |||
} | |||
/* Wrapper for page content to push down footer */ | |||
#wrap { | |||
min-height: 100%; | |||
height: auto; | |||
/* Negative indent footer by its height */ | |||
margin: auto; | |||
margin: 0 auto -140px; | |||
/* Pad bottom by footer height */ | |||
padding: 0 0 140px; | |||
} | |||
/* Set the fixed height of the footer here */ | |||
#wrap-footer { | |||
height: 140px; | |||
background-color: #f5f5f5; | |||
} | |||
.page-footer { | |||
margin: 20px 0px 0px; | |||
border-top: 1px solid #eee; | |||
} | |||
/* website group */ | |||
.view-selector { | |||
margin-bottom: 15px; | |||
} | |||
/* post and post list */ | |||
.post { | |||
padding: 15px 0px; | |||
word-wrap: break-word; | |||
border-bottom: 1px solid #eee; | |||
} | |||
.post:first-child { | |||
margin-top: 15px !important; | |||
} | |||
.post .img-responsive { | |||
border-radius: 4px; | |||
} | |||
.post .media-link { | |||
display: block; | |||
min-width: 50px; | |||
min-height: 50px; | |||
} | |||
.post .media-object { | |||
border-radius: 4px; | |||
max-width: 50px; | |||
} | |||
.post .media-heading { | |||
margin-bottom: 12px; | |||
} | |||
.parent-post .post { | |||
border: none; | |||
} | |||
.child-post { | |||
border: 1px solid #eee; | |||
padding-left: 15px; | |||
background-color: #f8f8f8; | |||
margin-top: 0px; | |||
} | |||
textarea { | |||
resize: vertical; | |||
} | |||
.post-add-textarea { | |||
height: 200px !important; | |||
} | |||
/* needs review */ | |||
.btn-small, .post-editor .btn { | |||
padding: 5px; | |||
font-size: 90%; | |||
} | |||
.btn-right, .post-editor .btn { | |||
margin-left: 5px; | |||
} | |||
.no-posts { | |||
margin-top: 15px; | |||
} | |||
.full-page { | |||
margin: 30px; | |||
} | |||
.img-responsive { | |||
border-radius: 4px; | |||
} | |||
.user-profile { | |||
min-height: 50px; | |||
min-width: 70px; | |||
} | |||
.visible-xs { | |||
display: none !important; | |||
} | |||
@media (max-width: 767px) { | |||
.visible-xs { | |||
display: inline-block !important; | |||
} | |||
} | |||
.nav-tabs > li > a { | |||
padding: 7px 10px; | |||
} | |||
.btn-more { | |||
margin-top: 15px; | |||
} | |||
.post-content img { | |||
margin: 10px 0px; | |||
} | |||
.assigned-label, .event-label { | |||
display: inline-block; | |||
padding: .4em .6em .4em; | |||
margin-bottom: 7px; | |||
} | |||
a.no-decoration { | |||
text-decoration: none; | |||
color: inherit; | |||
} | |||
.page-breadcrumbs { | |||
border-bottom: 1px solid #eee; | |||
} | |||
.page-breadcrumbs .breadcrumb { | |||
margin-bottom: 0px; | |||
background-color: transparent; | |||
border-radius: 0px; | |||
padding: 8px 0px; | |||
} | |||
@media (min-width: 768px) { | |||
.page-sidebar { | |||
padding-left: 5em; | |||
} | |||
} | |||
@media (max-width: 767px) { | |||
.page-sidebar { | |||
padding-bottom: 15px; | |||
margin-bottom: 15px; | |||
border-bottom: 1px solid #eee; | |||
} | |||
} | |||
.post:last-child { | |||
border-bottom: none; | |||
} | |||
/* end - needs review */ | |||
@@ -4,8 +4,7 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
import webnotes.webutils | |||
from webnotes.webutils import WebsiteGenerator, cleanup_page_name | |||
from webnotes.webutils import WebsiteGenerator, cleanup_page_name, clear_cache | |||
from webnotes import _ | |||
from webnotes.utils import today | |||
@@ -30,74 +29,11 @@ class DocType(WebsiteGenerator): | |||
def on_update(self): | |||
WebsiteGenerator.on_update(self) | |||
webnotes.webutils.delete_page_cache("writers") | |||
clear_cache("writers") | |||
def get_context(self): | |||
import webnotes.utils | |||
import markdown2 | |||
# this is for double precaution. usually it wont reach this code if not published | |||
if not webnotes.utils.cint(self.doc.published): | |||
raise Exception, "This blog has not been published yet!" | |||
# temp fields | |||
from webnotes.utils import global_date_format, get_fullname | |||
self.doc.full_name = get_fullname(self.doc.owner) | |||
self.doc.updated = global_date_format(self.doc.published_on) | |||
if self.doc.blogger: | |||
self.doc.blogger_info = webnotes.doc("Blogger", self.doc.blogger).fields | |||
self.doc.description = self.doc.blog_intro or self.doc.content[:140] | |||
self.doc.meta_description = self.doc.description | |||
self.doc.categories = webnotes.conn.sql_list("select name from `tabBlog Category` order by name") | |||
self.doc.comment_list = webnotes.conn.sql("""\ | |||
select comment, comment_by_fullname, creation | |||
from `tabComment` where comment_doctype="Blog Post" | |||
and comment_docname=%s order by creation""", (self.doc.name,), as_dict=1) or [] | |||
def clear_blog_cache(): | |||
for blog in webnotes.conn.sql_list("""select page_name from | |||
`tabBlog Post` where ifnull(published,0)=1"""): | |||
webnotes.webutils.delete_page_cache(blog) | |||
webnotes.webutils.delete_page_cache("writers") | |||
@webnotes.whitelist(allow_guest=True) | |||
def get_blog_list(start=0, by=None, category=None): | |||
import webnotes | |||
condition = "" | |||
if by: | |||
condition = " and t1.blogger='%s'" % by.replace("'", "\'") | |||
if category: | |||
condition += " and t1.blog_category='%s'" % category.replace("'", "\'") | |||
query = """\ | |||
select | |||
t1.title, t1.name, t1.page_name, t1.published_on as creation, | |||
ifnull(t1.blog_intro, t1.content) as content, | |||
t2.full_name, t2.avatar, t1.blogger, | |||
(select count(name) from `tabComment` where | |||
comment_doctype='Blog Post' and comment_docname=t1.name) as comments | |||
from `tabBlog Post` t1, `tabBlogger` t2 | |||
where ifnull(t1.published,0)=1 | |||
and t1.blogger = t2.name | |||
%(condition)s | |||
order by published_on desc, name asc | |||
limit %(start)s, 20""" % {"start": start, "condition": condition} | |||
result = webnotes.conn.sql(query, as_dict=1) | |||
# strip html tags from content | |||
import webnotes.utils | |||
clear_cache(blog) | |||
for res in result: | |||
from webnotes.utils import global_date_format | |||
res['published'] = global_date_format(res['creation']) | |||
if not res['content']: | |||
res['content'] = webnotes.webutils.get_html(res['page_name']) | |||
res['content'] = res['content'][:140] | |||
return result | |||
clear_cache("writers") |
@@ -0,0 +1,200 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.utils import get_fullname | |||
from webnotes.utils.email_lib.bulk import send | |||
from webnotes.utils.email_lib import sendmail | |||
from webnotes.utils.file_manager import save_file | |||
from webnotes.webutils import get_access | |||
from webnotes.templates.generators.website_group import clear_cache | |||
from webnotes.templates.website_group.post import clear_post_cache | |||
class DocType: | |||
def __init__(self, d, dl): | |||
self.doc, self.doclist = d, dl | |||
def validate(self): | |||
if not self.doc.parent_post and not self.doc.title: | |||
webnotes.throw("Please enter title!") | |||
self.assigned_to = webnotes.conn.get_value(self.doc.doctype, self.doc.name, "assigned_to") | |||
if self.doc.is_task: | |||
if not self.doc.status: | |||
self.doc.status = "Open" | |||
if self.doc.assigned_to: | |||
if not self.doc.assigned_to_fullname: | |||
self.doc.assigned_to_fullname = get_fullname(self.doc.assigned_to) | |||
else: | |||
self.doc.assigned_to_fullname = None | |||
else: | |||
self.doc.assigned_to = self.doc.assigned_to_fullname = self.doc.status = None | |||
if self.doc.is_event: | |||
if not self.doc.event_datetime: | |||
webnotes.throw("Please specify Event's Date and Time") | |||
else: | |||
self.doc.event_datetime = None | |||
def on_update(self): | |||
clear_cache(website_group=self.doc.website_group) | |||
clear_post_cache(self.doc.parent_post or self.doc.name) | |||
if self.doc.assigned_to and self.doc.assigned_to != self.assigned_to \ | |||
and webnotes.session.user != self.doc.assigned_to: | |||
# send assignment email | |||
sendmail(recipients=[self.doc.assigned_to], | |||
subject="You have been assigned this Task by {}".format(get_fullname(self.doc.modified_by)), | |||
msg=self.get_reply_email_message(self.doc.name, get_fullname(self.doc.owner))) | |||
def send_email_on_reply(self): | |||
owner_fullname = get_fullname(self.doc.owner) | |||
parent_post = webnotes.bean("Post", self.doc.parent_post).doc | |||
message = self.get_reply_email_message(self.doc.name, owner_fullname) | |||
# send email to the owner of the post, if he/she is different | |||
if parent_post.owner != self.doc.owner: | |||
send(recipients=[parent_post.owner], | |||
subject="{someone} replied to your post".format(someone=owner_fullname), | |||
message=message, | |||
# to allow unsubscribe | |||
doctype='Post', | |||
email_field='owner', | |||
# for tracking sent status | |||
ref_doctype=self.doc.doctype, ref_docname=self.doc.name) | |||
# send email to members who part of the conversation | |||
participants = webnotes.conn.sql("""select owner, name from `tabPost` | |||
where parent_post=%s and owner not in (%s, %s) order by creation asc""", | |||
(self.doc.parent_post, parent_post.owner, self.doc.owner), as_dict=True) | |||
send(recipients=[p.owner for p in participants], | |||
subject="{someone} replied to a post by {other}".format(someone=owner_fullname, | |||
other=get_fullname(parent_post.owner)), | |||
message=message, | |||
# to allow unsubscribe | |||
doctype='Post', | |||
email_field='owner', | |||
# for tracking sent status | |||
ref_doctype=self.doc.doctype, ref_docname=self.doc.name) | |||
def get_reply_email_message(self, post_name, owner_fullname=None): | |||
message = self.doc.content | |||
if self.doc.picture_url: | |||
message += """<div><img src="{url}" style="max-width: 100%"></div>"""\ | |||
.format(url=self.doc.picture_url) | |||
message += "<p>By {fullname}</p>".format(fullname=owner_fullname) | |||
message += "<p><a href='/post/{post_name}'>Click here to view the post</a></p>".format(fullname=owner_fullname, | |||
post_name=post_name) | |||
return message | |||
@webnotes.whitelist(allow_guest=True) | |||
def add_post(group, content, picture, picture_name, title=None, parent_post=None, | |||
assigned_to=None, status=None, event_datetime=None): | |||
access = get_access(group) | |||
if not access.get("write"): | |||
raise webnotes.PermissionError | |||
if parent_post: | |||
if webnotes.conn.get_value("Post", parent_post, "parent_post"): | |||
webnotes.throw("Cannot reply to a reply") | |||
group = webnotes.doc("Website Group", group) | |||
post = webnotes.bean({ | |||
"doctype":"Post", | |||
"title": (title or "").title(), | |||
"content": content, | |||
"website_group": group.name, | |||
"parent_post": parent_post or None | |||
}) | |||
if not parent_post: | |||
if group.group_type == "Tasks": | |||
post.doc.is_task = 1 | |||
post.doc.assigned_to = assigned_to | |||
elif group.group_type == "Events": | |||
post.doc.is_event = 1 | |||
post.doc.event_datetime = event_datetime | |||
post.ignore_permissions = True | |||
post.insert() | |||
if picture_name and picture: | |||
process_picture(post, picture_name, picture) | |||
# send email | |||
if parent_post: | |||
post.run_method("send_email_on_reply") | |||
return post.doc.parent_post or post.doc.name | |||
@webnotes.whitelist(allow_guest=True) | |||
def save_post(post, content, picture=None, picture_name=None, title=None, | |||
assigned_to=None, status=None, event_datetime=None): | |||
post = webnotes.bean("Post", post) | |||
access = get_access(post.doc.website_group) | |||
if not access.get("write"): | |||
raise webnotes.PermissionError | |||
# TODO improve error message | |||
if webnotes.session.user != post.doc.owner: | |||
for fieldname in ("title", "content"): | |||
if post.doc.fields.get(fieldname) != locals().get(fieldname): | |||
webnotes.throw("You cannot change: {}".format(fieldname.title())) | |||
if picture and picture_name: | |||
webnotes.throw("You cannot change: Picture") | |||
post.doc.fields.update({ | |||
"title": (title or "").title(), | |||
"content": content, | |||
"assigned_to": assigned_to, | |||
"status": status, | |||
"event_datetime": event_datetime | |||
}) | |||
post.ignore_permissions = True | |||
post.save() | |||
if picture_name and picture: | |||
process_picture(post, picture_name, picture) | |||
return post.doc.parent_post or post.doc.name | |||
def process_picture(post, picture_name, picture): | |||
file_data = save_file(picture_name, picture, "Post", post.doc.name, decode=True) | |||
post.doc.picture_url = file_data.file_name or file_data.file_url | |||
webnotes.conn.set_value("Post", post.doc.name, "picture_url", post.doc.picture_url) | |||
clear_cache(website_group=post.doc.website_group) | |||
@webnotes.whitelist() | |||
def suggest_user(group, term): | |||
"""suggest a user that has read permission in this group tree""" | |||
profiles = webnotes.conn.sql("""select | |||
pr.name, pr.first_name, pr.last_name, | |||
pr.user_image, pr.fb_location, pr.fb_hometown | |||
from `tabProfile` pr | |||
where (pr.first_name like %(term)s or pr.last_name like %(term)s) | |||
and pr.name not in ("Guest", "Administrator") is not null and pr.enabled=1""", | |||
{"term": "%{}%".format(term), "group": group}, as_dict=True) | |||
template = webnotes.get_template("templates/includes/profile_display.html") | |||
return [{ | |||
"value": "{} {}".format(pr.first_name or "", pr.last_name or "").strip(), | |||
"profile_html": template.render({"profile": pr}), | |||
"profile": pr.name | |||
} for pr in profiles] |
@@ -0,0 +1,146 @@ | |||
[ | |||
{ | |||
"creation": "2014-01-07 14:00:04", | |||
"docstatus": 0, | |||
"modified": "2014-01-29 16:27:45", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
{ | |||
"autoname": "P.#######", | |||
"doctype": "DocType", | |||
"document_type": "Transaction", | |||
"module": "Website", | |||
"name": "__common__" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"name": "__common__", | |||
"parent": "Post", | |||
"parentfield": "fields", | |||
"parenttype": "DocType", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"doctype": "DocPerm", | |||
"export": 1, | |||
"name": "__common__", | |||
"parent": "Post", | |||
"parentfield": "permissions", | |||
"parenttype": "DocType", | |||
"permlevel": 0, | |||
"read": 1, | |||
"report": 1, | |||
"role": "System Manager", | |||
"write": 1 | |||
}, | |||
{ | |||
"doctype": "DocType", | |||
"name": "Post" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"label": "Title", | |||
"reqd": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "content", | |||
"fieldtype": "Text", | |||
"in_list_view": 1, | |||
"label": "Content", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "picture_url", | |||
"fieldtype": "Attach", | |||
"label": "Picture URL" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "website_group", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Website Group", | |||
"options": "Website Group", | |||
"reqd": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "is_event", | |||
"fieldtype": "Check", | |||
"label": "Is Event" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "event_datetime", | |||
"fieldtype": "Datetime", | |||
"label": "Event Datetime" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "is_task", | |||
"fieldtype": "Check", | |||
"label": "Is Task" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "assigned_to", | |||
"fieldtype": "Link", | |||
"label": "Assigned To", | |||
"options": "Profile" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "assigned_to_fullname", | |||
"fieldtype": "Data", | |||
"label": "Assigned To Fullname" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "status", | |||
"fieldtype": "Select", | |||
"label": "Status", | |||
"options": "\nOpen\nClosed", | |||
"reqd": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "parent_post", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Parent Post", | |||
"options": "Post", | |||
"search_index": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "unsubscribe", | |||
"fieldtype": "Check", | |||
"label": "Unsubscribe" | |||
}, | |||
{ | |||
"default": "0", | |||
"doctype": "DocField", | |||
"fieldname": "upvotes", | |||
"fieldtype": "Int", | |||
"label": "Upvotes" | |||
}, | |||
{ | |||
"default": "0", | |||
"doctype": "DocField", | |||
"fieldname": "replies", | |||
"fieldtype": "Int", | |||
"label": "Replies" | |||
}, | |||
{ | |||
"doctype": "DocPerm" | |||
} | |||
] |
@@ -0,0 +1,53 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import get_access | |||
class DocType: | |||
def __init__(self, d, dl): | |||
self.doc, self.doclist = d, dl | |||
def validate(self): | |||
# if new | |||
if self.doc.fields.get("__islocal"): | |||
if webnotes.conn.get_value("User Vote", {"ref_doctype": self.doc.ref_doctype, | |||
"ref_name": self.doc.ref_name, "owner": webnotes.session.user}): | |||
raise webnotes.DuplicateEntryError | |||
def on_update(self): | |||
self.update_ref_count() | |||
def on_trash(self): | |||
self.update_ref_count(-1) | |||
def update_ref_count(self, cnt=0): | |||
count = webnotes.conn.sql("""select count(*) from `tabUser Vote` where ref_doctype=%s and ref_name=%s""", | |||
(self.doc.ref_doctype, self.doc.ref_name))[0][0] | |||
webnotes.conn.set_value(self.doc.ref_doctype, self.doc.ref_name, "upvotes", count + cnt) | |||
def on_doctype_update(): | |||
webnotes.conn.add_index("User Vote", ["ref_doctype", "ref_name"]) | |||
# don't allow guest to give vote | |||
@webnotes.whitelist() | |||
def set_vote(ref_doctype, ref_name): | |||
website_group = webnotes.conn.get_value(ref_doctype, ref_name, "website_group") | |||
if not get_access(website_group).get("read"): | |||
raise webnotes.PermissionError | |||
try: | |||
user_vote = webnotes.bean({ | |||
"doctype": "User Vote", | |||
"ref_doctype": ref_doctype, | |||
"ref_name": ref_name | |||
}) | |||
user_vote.ignore_permissions = True | |||
user_vote.insert() | |||
return "ok" | |||
except webnotes.DuplicateEntryError: | |||
return "duplicate" |
@@ -0,0 +1,61 @@ | |||
[ | |||
{ | |||
"creation": "2014-01-17 16:26:21", | |||
"docstatus": 0, | |||
"modified": "2014-01-21 15:45:30", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
{ | |||
"autoname": "_VOTE.#######", | |||
"doctype": "DocType", | |||
"document_type": "Transaction", | |||
"module": "Website", | |||
"name": "__common__" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"name": "__common__", | |||
"parent": "User Vote", | |||
"parentfield": "fields", | |||
"parenttype": "DocType", | |||
"permlevel": 0, | |||
"search_index": 0 | |||
}, | |||
{ | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"doctype": "DocPerm", | |||
"export": 1, | |||
"name": "__common__", | |||
"parent": "User Vote", | |||
"parentfield": "permissions", | |||
"parenttype": "DocType", | |||
"permlevel": 0, | |||
"read": 1, | |||
"report": 1, | |||
"role": "System Manager", | |||
"write": 1 | |||
}, | |||
{ | |||
"doctype": "DocType", | |||
"name": "User Vote" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "ref_doctype", | |||
"fieldtype": "Link", | |||
"label": "Ref DocType", | |||
"options": "DocType" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "ref_name", | |||
"fieldtype": "Data", | |||
"label": "Ref Name" | |||
}, | |||
{ | |||
"doctype": "DocPerm" | |||
} | |||
] |
@@ -37,81 +37,3 @@ class DocType(WebsiteGenerator): | |||
if self.doclist.get({"parentfield": "toc"}): | |||
from webnotes.webutils import clear_cache | |||
clear_cache() | |||
def get_context(self): | |||
if self.doc.slideshow: | |||
from webnotes.website.doctype.website_slideshow.website_slideshow import get_slideshow | |||
get_slideshow(self) | |||
self.doc.meta_description = self.doc.description | |||
self.doc.breadcrumbs = self.get_breadcrumbs() | |||
self.doc.toc_list = self.get_toc_list() | |||
# parent, child, next sibling links | |||
self.doc.links = self.get_navigation_links() | |||
if self.doc.enable_comments: | |||
self.doc.comment_list = webnotes.conn.sql("""select | |||
comment, comment_by_fullname, creation | |||
from `tabComment` where comment_doctype="Web Page" | |||
and comment_docname=%s order by creation""", self.doc.name, as_dict=1) or [] | |||
def get_breadcrumbs(self): | |||
breadcrumbs = [] | |||
def add_parent_of(web_page): | |||
parent = webnotes.conn.sql("""select name, page_name, title from `tabWeb Page` | |||
where exists (select parent from `tabTable of Contents` | |||
where `tabTable of Contents`.parent=`tabWeb Page`.name | |||
and web_page=%s)""", web_page, as_dict=True) | |||
if parent and parent[0]: | |||
parent = parent[0] | |||
add_parent_of(parent.name) | |||
breadcrumbs.append(parent) | |||
add_parent_of(self.doc.name) | |||
return breadcrumbs | |||
def get_toc_list(self): | |||
toc_list = self.doclist.get({"parentfield": "toc"}) | |||
if not toc_list: return [] | |||
out = webnotes.conn.sql("""select name, page_name, title | |||
from `tabWeb Page` where name in (%s)""" % \ | |||
(", ".join(["%s"]*len(toc_list))), | |||
tuple([d.web_page for d in toc_list]), | |||
as_dict=True) | |||
toc_idx = dict(((toc.web_page, toc.idx) for toc in toc_list)) | |||
return sorted(out, key=lambda x: toc_idx.get(x.name)) | |||
def get_navigation_links(self): | |||
links = {} | |||
if self.doc.toc_list: | |||
links["child"] = self.doc.toc_list[0] | |||
if self.doc.breadcrumbs: | |||
if self.doc.breadcrumbs[-1]: | |||
links["parent"] = self.doc.breadcrumbs[-1] | |||
def set_next(current, parent, breadcrumbs): | |||
web_page = webnotes.get_obj("Web Page", parent) | |||
toc_list = web_page.get_toc_list() | |||
for i, toc in enumerate(toc_list): | |||
if toc.name == current and ((i+1)<len(toc_list)): | |||
links["next"] = toc_list[i+1] | |||
break | |||
if not links.get("next") and breadcrumbs: | |||
set_next(parent, breadcrumbs[-1].name, breadcrumbs[:-1]) | |||
set_next(self.doc.name, self.doc.breadcrumbs[-1].name, self.doc.breadcrumbs[:-1]) | |||
return links | |||
@@ -2,7 +2,7 @@ | |||
{ | |||
"creation": "2013-03-28 10:35:30", | |||
"docstatus": 0, | |||
"modified": "2014-01-20 17:49:35", | |||
"modified": "2014-02-05 17:02:09", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
@@ -185,6 +185,13 @@ | |||
"label": "Table of Contents", | |||
"options": "Table of Contents" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "parent_website_sitemap", | |||
"fieldtype": "Link", | |||
"label": "Parent Website Page", | |||
"options": "Website Sitemap" | |||
}, | |||
{ | |||
"doctype": "DocPerm" | |||
} |
@@ -0,0 +1,32 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes.webutils import WebsiteGenerator, cleanup_page_name | |||
from webnotes.templates.generators.website_group import get_context | |||
class DocType(WebsiteGenerator): | |||
def __init__(self, d, dl): | |||
self.doc, self.doclist = d, dl | |||
def autoname(self): | |||
self.validate_group_name() | |||
self.doc.name = self.doc.group_name | |||
def validate(self): | |||
# TODO use titlecase package | |||
self.doc.group_title = self.doc.group_title.title() | |||
self.validate_page_name() | |||
def validate_group_name(self): | |||
self.doc.group_name = cleanup_page_name(self.doc.group_name or self.doc.group_title) | |||
def validate_page_name(self): | |||
self.doc.page_name = cleanup_page_name(self.doc.page_name or self.doc.group_name) | |||
if not self.doc.page_name: | |||
webnotes.throw(_("Page Name is mandatory"), raise_exception=webnotes.MandatoryError) | |||
def get_page_title(self): | |||
return self.doc.group_title |
@@ -0,0 +1,118 @@ | |||
[ | |||
{ | |||
"creation": "2014-01-29 15:57:42", | |||
"docstatus": 0, | |||
"modified": "2014-02-05 17:00:33", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
{ | |||
"doctype": "DocType", | |||
"document_type": "Master", | |||
"module": "Website", | |||
"name": "__common__" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"name": "__common__", | |||
"parent": "Website Group", | |||
"parentfield": "fields", | |||
"parenttype": "DocType", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"doctype": "DocPerm", | |||
"export": 1, | |||
"name": "__common__", | |||
"parent": "Website Group", | |||
"parentfield": "permissions", | |||
"parenttype": "DocType", | |||
"permlevel": 0, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Website Manager", | |||
"write": 1 | |||
}, | |||
{ | |||
"doctype": "DocType", | |||
"name": "Website Group" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "group_name", | |||
"fieldtype": "Data", | |||
"label": "Group Name", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "group_title", | |||
"fieldtype": "Data", | |||
"label": "Group Title", | |||
"no_copy": 0, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "group_type", | |||
"fieldtype": "Select", | |||
"label": "Group Type", | |||
"options": "Forum\nTasks\nEvents", | |||
"reqd": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "group_description", | |||
"fieldtype": "Text", | |||
"label": "Group Description" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "page_name", | |||
"fieldtype": "Data", | |||
"in_list_view": 1, | |||
"label": "Page Name", | |||
"no_copy": 1, | |||
"reqd": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "public_read", | |||
"fieldtype": "Check", | |||
"label": "Anyone Can Read" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "public_write", | |||
"fieldtype": "Check", | |||
"label": "Anyone Can Write" | |||
}, | |||
{ | |||
"description": "Display in the sidebar of this Website Sitemap node", | |||
"doctype": "DocField", | |||
"fieldname": "parent_website_sitemap", | |||
"fieldtype": "Link", | |||
"in_list_view": 0, | |||
"label": "Parent Website Page", | |||
"options": "Website Sitemap" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "upvotes", | |||
"fieldtype": "Int", | |||
"label": "Upvotes", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "replies", | |||
"fieldtype": "Int", | |||
"label": "Replies", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocPerm" | |||
} | |||
] |
@@ -2,7 +2,7 @@ | |||
{ | |||
"creation": "2013-04-30 12:58:46", | |||
"docstatus": 0, | |||
"modified": "2013-12-27 16:37:52", | |||
"modified": "2014-02-03 15:25:54", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
@@ -25,6 +25,8 @@ | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"cancel": 0, | |||
"delete": 0, | |||
"doctype": "DocPerm", | |||
"name": "__common__", | |||
"parent": "Website Settings", | |||
@@ -48,8 +50,9 @@ | |||
"description": "Link that is the website home page. Standard Links (index, login, products, blog, about, contact)", | |||
"doctype": "DocField", | |||
"fieldname": "home_page", | |||
"fieldtype": "Data", | |||
"fieldtype": "Link", | |||
"label": "Home Page", | |||
"options": "Website Sitemap", | |||
"reqd": 0 | |||
}, | |||
{ | |||
@@ -241,7 +244,6 @@ | |||
}, | |||
{ | |||
"amend": 0, | |||
"cancel": 0, | |||
"create": 0, | |||
"doctype": "DocPerm", | |||
"permlevel": 1, | |||
@@ -5,17 +5,96 @@ | |||
from __future__ import unicode_literals | |||
import webnotes | |||
from webnotes import _ | |||
from webnotes.utils.nestedset import DocTypeNestedSet | |||
class DocType: | |||
sitemap_fields = ("page_name", "ref_doctype", "docname", "page_or_generator", | |||
"lastmod", "parent_website_sitemap", "public_read", "public_write", "page_title") | |||
class DocType(DocTypeNestedSet): | |||
def __init__(self, d, dl): | |||
self.doc, self.doclist = d, dl | |||
self.nsm_parent_field = "parent_website_sitemap" | |||
def autoname(self): | |||
self.doc.name = self.doc.page_name | |||
def validate(self): | |||
self.check_if_page_name_is_unique() | |||
self.make_private_if_parent_is_private() | |||
def on_update(self): | |||
if not webnotes.flags.in_rebuild_config: | |||
DocTypeNestedSet.on_update(self) | |||
def check_if_page_name_is_unique(self): | |||
exists = False | |||
if self.doc.page_or_generator == "Page": | |||
# for a page, name and website sitemap config form a unique key | |||
exists = webnotes.conn.sql("""select name from `tabWebsite Sitemap` | |||
where name=%s and website_sitemap_config!=%s""", (self.doc.name, self.doc.website_sitemap_config)) | |||
else: | |||
# for a generator, name, ref_doctype and docname make a unique key | |||
exists = webnotes.conn.sql("""select name from `tabWebsite Sitemap` | |||
where name=%s and (ifnull(ref_doctype, '')!=%s or ifnull(docname, '')!=%s)""", | |||
(self.doc.name, self.doc.ref_doctype, self.doc.docname)) | |||
if exists: | |||
webnotes.throw("{}: {}. {}.".format(_("A Website Page already exists with the Page Name"), | |||
self.doc.name, _("Please change it to continue"))) | |||
def make_private_if_parent_is_private(self): | |||
if self.doc.parent_website_sitemap: | |||
parent_pubic_read = webnotes.conn.get_value("Website Sitemap", self.doc.parent_website_sitemap, | |||
"public_read") | |||
if not parent_pubic_read: | |||
self.doc.public_read = self.doc.public_write = 0 | |||
def on_trash(self): | |||
from webnotes.webutils import clear_cache | |||
# remove website sitemap permissions | |||
to_remove = webnotes.conn.sql_list("""select name from `tabWebsite Sitemap Permission` | |||
where website_sitemap=%s""", (self.doc.name,)) | |||
webnotes.delete_doc("Website Sitemap Permission", to_remove, ignore_permissions=True) | |||
clear_cache(self.doc.name) | |||
def add_to_sitemap(options): | |||
doc = webnotes.doc({"doctype":"Website Sitemap"}) | |||
for key in ("page_name", "docname", "page_or_generator", "lastmod"): | |||
doc.fields[key] = options.get(key) | |||
if not doc.page_name: | |||
doc.page_name = options.link_name | |||
doc.name = doc.page_name | |||
doc.website_sitemap_config = options.link_name | |||
doc.insert() | |||
bean = webnotes.new_bean("Website Sitemap") | |||
for key in sitemap_fields: | |||
bean.doc.fields[key] = options.get(key) | |||
if not bean.doc.page_name: | |||
bean.doc.page_name = options.link_name | |||
bean.doc.website_sitemap_config = options.link_name | |||
bean.insert(ignore_permissions=True) | |||
def update_sitemap(website_sitemap, options): | |||
bean = webnotes.bean("Website Sitemap", website_sitemap) | |||
for key in sitemap_fields: | |||
bean.doc.fields[key] = options.get(key) | |||
if not bean.doc.page_name: | |||
bean.doc.page_name = options.link_name | |||
bean.doc.website_sitemap_config = options.link_name | |||
bean.save(ignore_permissions=True) | |||
def remove_sitemap(page_name=None, ref_doctype=None, docname=None): | |||
if page_name: | |||
webnotes.delete_doc("Website Sitemap", page_name, ignore_permissions=True) | |||
elif ref_doctype and docname: | |||
webnotes.delete_doc("Website Sitemap", webnotes.conn.sql_list("""select name from `tabWebsite Sitemap` | |||
where ref_doctype=%s and docname=%s""", (ref_doctype, docname)), ignore_permissions=True) | |||
def cleanup_sitemap(): | |||
"""remove sitemap records where its config do not exist anymore""" | |||
to_delete = webnotes.conn.sql_list("""select name from `tabWebsite Sitemap` ws | |||
where not exists(select name from `tabWebsite Sitemap Config` wsc | |||
where wsc.name=ws.website_sitemap_config)""") | |||
webnotes.delete_doc("Website Sitemap", to_delete, ignore_permissions=True) |
@@ -2,11 +2,12 @@ | |||
{ | |||
"creation": "2013-11-18 15:38:40", | |||
"docstatus": 0, | |||
"modified": "2013-12-20 19:24:40", | |||
"modified": "2014-01-30 16:50:49", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
{ | |||
"allow_rename": 1, | |||
"autoname": "field:page_name", | |||
"doctype": "DocType", | |||
"module": "Website", | |||
@@ -20,6 +21,19 @@ | |||
"parenttype": "DocType", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"create": 0, | |||
"doctype": "DocPerm", | |||
"name": "__common__", | |||
"parent": "Website Sitemap", | |||
"parentfield": "permissions", | |||
"parenttype": "DocType", | |||
"permlevel": 0, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Website Manager", | |||
"write": 1 | |||
}, | |||
{ | |||
"doctype": "DocType", | |||
"name": "Website Sitemap" | |||
@@ -37,8 +51,24 @@ | |||
"fieldname": "page_name", | |||
"fieldtype": "Data", | |||
"label": "Page Name", | |||
"read_only": 1, | |||
"reqd": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "page_title", | |||
"fieldtype": "Data", | |||
"label": "Page Title", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "ref_doctype", | |||
"fieldtype": "Link", | |||
"label": "Ref DocType", | |||
"options": "DocType", | |||
"reqd": 0 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "docname", | |||
@@ -58,5 +88,56 @@ | |||
"fieldtype": "Link", | |||
"label": "Website Sitemap Config", | |||
"options": "Website Sitemap Config" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "parent_website_sitemap", | |||
"fieldtype": "Link", | |||
"in_list_view": 1, | |||
"label": "Parent Website Sitemap", | |||
"options": "Website Sitemap", | |||
"search_index": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "lft", | |||
"fieldtype": "Int", | |||
"hidden": 1, | |||
"label": "lft", | |||
"read_only": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "rgt", | |||
"fieldtype": "Int", | |||
"hidden": 1, | |||
"in_list_view": 0, | |||
"label": "rgt", | |||
"read_only": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "old_parent", | |||
"fieldtype": "Data", | |||
"hidden": 1, | |||
"label": "Old Parent", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "public_read", | |||
"fieldtype": "Check", | |||
"label": "Anyone Can Read" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "public_write", | |||
"fieldtype": "Check", | |||
"label": "Anyone Can Write" | |||
}, | |||
{ | |||
"doctype": "DocPerm" | |||
} | |||
] |
@@ -8,15 +8,23 @@ import webnotes | |||
import webnotes.utils | |||
import os | |||
from webnotes.website.doctype.website_sitemap.website_sitemap import add_to_sitemap | |||
from webnotes.website.doctype.website_sitemap.website_sitemap import add_to_sitemap, update_sitemap, cleanup_sitemap | |||
from webnotes.utils.nestedset import rebuild_tree | |||
class DocType: | |||
def __init__(self, d, dl): | |||
self.doc, self.doclist = d, dl | |||
def after_insert(self): | |||
if self.doc.page_or_generator == "Page": | |||
add_to_sitemap(self.doc.fields) | |||
website_sitemap = webnotes.conn.get_value("Website Sitemap", | |||
{"website_sitemap_config": self.doc.name, "page_or_generator": "Page"}) | |||
if website_sitemap: | |||
update_sitemap(website_sitemap, self.doc.fields) | |||
else: | |||
add_to_sitemap(self.doc.fields) | |||
else: | |||
condition = "" | |||
if self.doc.condition_field: | |||
@@ -25,17 +33,24 @@ class DocType: | |||
for name in webnotes.conn.sql_list("""select name from `tab%s` %s""" \ | |||
% (self.doc.ref_doctype, condition)): | |||
webnotes.bean(self.doc.ref_doctype, name).run_method("on_update") | |||
def on_trash(self): | |||
webnotes.conn.sql("""delete from `tabWebsite Sitemap` | |||
where website_sitemap_config = %s""", self.doc.name) | |||
def rebuild_website_sitemap_config(): | |||
# TODO | |||
webnotes.flags.in_rebuild_config = True | |||
webnotes.conn.sql("""delete from `tabWebsite Sitemap Config`""") | |||
webnotes.conn.sql("""delete from `tabWebsite Sitemap`""") | |||
for app in webnotes.get_installed_apps(): | |||
build_website_sitemap_config(app) | |||
cleanup_sitemap() | |||
webnotes.flags.in_rebuild_config = False | |||
# enable nested set and rebuild | |||
rebuild_tree("Website Sitemap", "parent_website_sitemap") | |||
webnotes.conn.commit() | |||
def build_website_sitemap_config(app): | |||
config = {"pages": {}, "generators":{}} | |||
basepath = webnotes.get_pymodule_path(app) | |||
@@ -75,10 +90,11 @@ def add_website_sitemap_config(page_or_generator, app, path, fname, basepath): | |||
wsc.ref_doctype = getattr(module, "doctype", None) | |||
wsc.page_name_field = getattr(module, "page_name_field", "page_name") | |||
wsc.condition_field = getattr(module, "condition_field", None) | |||
wsc.base_template_path = getattr(module, "base_template_path", None) | |||
if webnotes.conn.exists("Website Sitemap Config", wsc.link_name): | |||
# found by earlier app, override | |||
webnotes.delete_doc("Website Sitemap Config", wsc.link_name) | |||
webnotes.conn.sql("""delete from `tabWebsite Sitemap Config` where name=%s""", (wsc.link_name,)) | |||
webnotes.bean(wsc).insert() | |||
@@ -2,7 +2,7 @@ | |||
{ | |||
"creation": "2013-11-18 15:35:00", | |||
"docstatus": 0, | |||
"modified": "2013-12-20 19:24:40", | |||
"modified": "2014-01-30 17:25:27", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
@@ -21,6 +21,20 @@ | |||
"parenttype": "DocType", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"create": 0, | |||
"doctype": "DocPerm", | |||
"export": 0, | |||
"name": "__common__", | |||
"parent": "Website Sitemap Config", | |||
"parentfield": "permissions", | |||
"parenttype": "DocType", | |||
"permlevel": 0, | |||
"read": 1, | |||
"report": 1, | |||
"role": "System Manager", | |||
"write": 0 | |||
}, | |||
{ | |||
"doctype": "DocType", | |||
"name": "Website Sitemap Config" | |||
@@ -48,6 +62,13 @@ | |||
"label": "Link Name", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "base_template_path", | |||
"fieldtype": "Data", | |||
"label": "Base Template Path", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "template_path", | |||
@@ -95,5 +116,8 @@ | |||
"fieldtype": "Data", | |||
"label": "Condition Field", | |||
"read_only": 1 | |||
}, | |||
{ | |||
"doctype": "DocPerm" | |||
} | |||
] |
@@ -0,0 +1,79 @@ | |||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import webnotes | |||
class DocType: | |||
def __init__(self, d, dl): | |||
self.doc, self.doclist = d, dl | |||
def on_update(self): | |||
remove_empty_permissions() | |||
clear_permissions(self.doc.profile) | |||
def remove_empty_permissions(): | |||
permissions_cache_to_be_cleared = webnotes.conn.sql_list("""select distinct profile | |||
from `tabWebsite Sitemap Permission` | |||
where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""") | |||
webnotes.conn.sql("""delete from `tabWebsite Sitemap Permission` | |||
where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""") | |||
clear_permissions(permissions_cache_to_be_cleared) | |||
def get_access(sitemap_page, profile=None): | |||
profile = profile or webnotes.session.user | |||
key = "website_sitemap_permissions:{}".format(profile) | |||
cache = webnotes.cache() | |||
permissions = cache.get_value(key) or {} | |||
if not permissions.get(sitemap_page): | |||
permissions[sitemap_page] = _get_access(sitemap_page, profile) | |||
cache.set_value(key, permissions) | |||
return permissions.get(sitemap_page) | |||
def _get_access(sitemap_page, profile): | |||
lft, rgt, public_read, public_write = webnotes.conn.get_value("Website Sitemap", sitemap_page, | |||
["lft", "rgt", "public_read", "public_write"]) | |||
if not (lft and rgt): | |||
raise webnotes.ValidationError("Please rebuild Website Sitemap Tree") | |||
if profile == "Guest": | |||
return { "read": public_read, "write": 0, "admin": 0 } | |||
read = write = admin = private_read = 0 | |||
if public_write: | |||
read = write = 1 | |||
elif public_read: | |||
read = 1 | |||
for perm in webnotes.conn.sql("""select wsp.`read`, wsp.`write`, wsp.`admin`, | |||
ws.lft, ws.rgt, ws.name | |||
from `tabWebsite Sitemap Permission` wsp, `tabWebsite Sitemap` ws | |||
where wsp.profile = %s and wsp.website_sitemap = ws.name | |||
order by lft asc""", (profile,), as_dict=True): | |||
if perm.lft <= lft and perm.rgt >= rgt: | |||
if not (public_read or private_read): private_read = perm.read | |||
if not read: read = perm.read | |||
if not write: write = perm.write | |||
if not admin: admin = perm.admin | |||
if write: read = write | |||
if read and write and admin: | |||
break | |||
return { "read": read, "write": write, "admin": admin, "private_read": private_read } | |||
def clear_permissions(profiles=None): | |||
if isinstance(profiles, basestring): | |||
profiles = [profiles] | |||
elif profiles is None: | |||
profiles = webnotes.conn.sql_list("""select name from `tabProfile`""") | |||
cache = webnotes.cache() | |||
for profile in profiles: | |||
cache.delete_value("website_sitemap_permissions:{}".format(profile)) |
@@ -0,0 +1,83 @@ | |||
[ | |||
{ | |||
"creation": "2014-01-29 17:56:29", | |||
"docstatus": 0, | |||
"modified": "2014-01-29 18:05:29", | |||
"modified_by": "Administrator", | |||
"owner": "Administrator" | |||
}, | |||
{ | |||
"autoname": "WSP.######", | |||
"doctype": "DocType", | |||
"module": "Website", | |||
"name": "__common__" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"in_list_view": 1, | |||
"name": "__common__", | |||
"parent": "Website Sitemap Permission", | |||
"parentfield": "fields", | |||
"parenttype": "DocType", | |||
"permlevel": 0 | |||
}, | |||
{ | |||
"create": 1, | |||
"delete": 1, | |||
"doctype": "DocPerm", | |||
"export": 1, | |||
"import": 0, | |||
"name": "__common__", | |||
"parent": "Website Sitemap Permission", | |||
"parentfield": "permissions", | |||
"parenttype": "DocType", | |||
"permlevel": 0, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Website Manager", | |||
"write": 1 | |||
}, | |||
{ | |||
"doctype": "DocType", | |||
"name": "Website Sitemap Permission" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "website_sitemap", | |||
"fieldtype": "Link", | |||
"label": "Website Sitemap", | |||
"options": "Website Sitemap", | |||
"reqd": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "profile", | |||
"fieldtype": "Link", | |||
"label": "Profile", | |||
"options": "Profile", | |||
"reqd": 1, | |||
"search_index": 1 | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "read", | |||
"fieldtype": "Check", | |||
"label": "Read" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "write", | |||
"fieldtype": "Check", | |||
"label": "Write" | |||
}, | |||
{ | |||
"doctype": "DocField", | |||
"fieldname": "admin", | |||
"fieldtype": "Check", | |||
"label": "Admin" | |||
}, | |||
{ | |||
"doctype": "DocPerm" | |||
} | |||
] |
@@ -15,7 +15,10 @@ class DocType: | |||
from webnotes.webutils import clear_cache | |||
clear_cache() | |||
def get_slideshow(obj): | |||
slideshow = webnotes.bean("Website Slideshow", obj.doc.slideshow) | |||
obj.slides = slideshow.doclist.get({"doctype":"Website Slideshow Item"}) | |||
obj.doc.slideshow_header = slideshow.doc.header or "" | |||
def get_slideshow(bean): | |||
slideshow = webnotes.bean("Website Slideshow", bean.doc.slideshow) | |||
return { | |||
"slides": slideshow.doclist.get({"doctype":"Website Slideshow Item"}), | |||
"slideshow_header": slideshow.doc.header or "" | |||
} |