浏览代码

[cleanup] remove website group

version-14
Rushabh Mehta 10 年前
committed by Anand Doshi
父节点
当前提交
94b9f819fb
共有 63 个文件被更改,包括 10 次插入2552 次删除
  1. +0
    -10
      frappe/config/website.py
  2. +1
    -9
      frappe/hooks.py
  3. +1
    -0
      frappe/patches.txt
  4. +0
    -0
      frappe/patches/v4_0/__init__.py
  5. +0
    -12
      frappe/patches/v4_0/add_delete_permission.py
  6. +0
    -23
      frappe/patches/v4_0/change_varchar_length.py
  7. +0
    -39
      frappe/patches/v4_0/create_custom_field_for_owner_match.py
  8. +0
    -10
      frappe/patches/v4_0/deprecate_control_panel.py
  9. +0
    -13
      frappe/patches/v4_0/deprecate_link_selects.py
  10. +0
    -14
      frappe/patches/v4_0/enable_scheduler_in_system_settings.py
  11. +0
    -36
      frappe/patches/v4_0/file_manager_hooks.py
  12. +0
    -13
      frappe/patches/v4_0/fix_attach_field_file_url.py
  13. +0
    -11
      frappe/patches/v4_0/private_backups.py
  14. +0
    -4
      frappe/patches/v4_0/remove_index_sitemap.py
  15. +0
    -10
      frappe/patches/v4_0/remove_old_parent.py
  16. +0
    -10
      frappe/patches/v4_0/remove_user_owner_custom_field.py
  17. +0
    -18
      frappe/patches/v4_0/rename_profile_to_user.py
  18. +0
    -31
      frappe/patches/v4_0/rename_sitemap_to_route.py
  19. +0
    -21
      frappe/patches/v4_0/replace_deprecated_timezones.py
  20. +0
    -10
      frappe/patches/v4_0/set_module_in_report.py
  21. +0
    -8
      frappe/patches/v4_0/set_todo_checked_as_closed.py
  22. +0
    -11
      frappe/patches/v4_0/set_user_gravatar.py
  23. +0
    -24
      frappe/patches/v4_0/set_user_permissions.py
  24. +0
    -24
      frappe/patches/v4_0/set_website_route_idx.py
  25. +0
    -18
      frappe/patches/v4_0/update_custom_field_insert_after.py
  26. +0
    -11
      frappe/patches/v4_0/update_datetime.py
  27. +0
    -11
      frappe/patches/v4_0/webnotes_to_frappe.py
  28. +0
    -21
      frappe/patches/v4_0/website_sitemap_hierarchy.py
  29. +0
    -0
      frappe/patches/v4_1/__init__.py
  30. +0
    -11
      frappe/patches/v4_1/enable_outgoing_email_settings.py
  31. +0
    -24
      frappe/patches/v4_1/enable_print_as_pdf.py
  32. +0
    -98
      frappe/patches/v4_1/file_manager_fix.py
  33. +0
    -0
      frappe/patches/v4_2/__init__.py
  34. +0
    -11
      frappe/patches/v4_2/print_with_letterhead.py
  35. +0
    -7
      frappe/patches/v4_2/refactor_website_routing.py
  36. +0
    -10
      frappe/patches/v4_2/set_assign_in_doc.py
  37. +7
    -0
      frappe/patches/v5_0/clear_website_group.py
  38. +0
    -0
      frappe/templates/website_group/__init__.py
  39. +0
    -19
      frappe/templates/website_group/edit_post.html
  40. +0
    -27
      frappe/templates/website_group/forum.html
  41. +0
    -64
      frappe/templates/website_group/forum.py
  42. +0
    -33
      frappe/templates/website_group/post.html
  43. +0
    -156
      frappe/templates/website_group/post.py
  44. +0
    -77
      frappe/templates/website_group/settings.html
  45. +0
    -104
      frappe/templates/website_group/settings.py
  46. +1
    -5
      frappe/website/context.py
  47. +0
    -0
      frappe/website/doctype/post/__init__.py
  48. +0
    -128
      frappe/website/doctype/post/post.json
  49. +0
    -99
      frappe/website/doctype/post/post.py
  50. +0
    -0
      frappe/website/doctype/user_vote/__init__.py
  51. +0
    -43
      frappe/website/doctype/user_vote/user_vote.json
  52. +0
    -55
      frappe/website/doctype/user_vote/user_vote.py
  53. +0
    -0
      frappe/website/doctype/website_group/__init__.py
  54. +0
    -7
      frappe/website/doctype/website_group/test_records.json
  55. +0
    -10
      frappe/website/doctype/website_group/test_website_group.py
  56. +0
    -153
      frappe/website/doctype/website_group/website_group.json
  57. +0
    -251
      frappe/website/doctype/website_group/website_group.py
  58. +0
    -0
      frappe/website/doctype/website_route_permission/__init__.py
  59. +0
    -79
      frappe/website/doctype/website_route_permission/website_route_permission.json
  60. +0
    -16
      frappe/website/doctype/website_route_permission/website_route_permission.py
  61. +0
    -564
      frappe/website/js/website_group.js
  62. +0
    -77
      frappe/website/permissions.py
  63. +0
    -2
      frappe/website/render.py

+ 0
- 10
frappe/config/website.py 查看文件

@@ -26,16 +26,6 @@ def get_data():
"name": "Blogger",
"description": _("User ID of a blog writer."),
},
{
"type": "doctype",
"name": "Website Group",
"description": _("Web Site Forum Page."),
},
{
"type": "doctype",
"name": "Post",
"description": _("List of Web Site Forum's Posts."),
},
{
"type": "doctype",
"name": "Website Slideshow",


+ 1
- 9
frappe/hooks.py 查看文件

@@ -25,15 +25,13 @@ web_include_css = [
"style_settings.css"
]

website_clear_cache = "frappe.website.doctype.website_group.website_group.clear_cache"

write_file_keys = ["file_url", "file_name"]

notification_config = "frappe.core.notifications.get_notification_config"

before_tests = "frappe.utils.install.before_tests"

website_generators = ["Web Page", "Blog Post", "Website Group", "Blog Category", "Web Form"]
website_generators = ["Web Page", "Blog Post", "Blog Category", "Web Form"]

# login

@@ -76,9 +74,6 @@ doc_events = {
"frappe.email.doctype.email_alert.email_alert.trigger_email_alerts"
],
"on_trash": "frappe.core.doctype.notification_count.notification_count.clear_doctype_notifications"
},
"Website Route Permission": {
"on_update": "frappe.website.doctype.website_group.website_group.clear_cache_on_doc_event"
}
}

@@ -93,8 +88,5 @@ scheduler_events = {
"frappe.desk.doctype.event.event.send_event_digest",
"frappe.sessions.clear_expired_sessions",
"frappe.email.doctype.email_alert.email_alert.trigger_daily_alerts",
],
"hourly": [
"frappe.website.doctype.website_group.website_group.clear_event_cache"
]
}

+ 1
- 0
frappe/patches.txt 查看文件

@@ -57,3 +57,4 @@ frappe.patches.v4_2.refactor_website_routing
frappe.patches.v4_2.set_assign_in_doc
frappe.patches.v4_3.remove_allow_on_submit_customization
frappe.patches.v5_0.communication_parent
frappe.patches.v5_0.clear_website_group

+ 0
- 0
frappe/patches/v4_0/__init__.py 查看文件


+ 0
- 12
frappe/patches/v4_0/add_delete_permission.py 查看文件

@@ -1,12 +0,0 @@
import frappe

def execute():
frappe.reload_doc("core", "doctype", "docperm")
# delete same as cancel (map old permissions)
frappe.db.sql("""update tabDocPerm set `delete`=ifnull(`cancel`,0)""")
# can't cancel if can't submit
frappe.db.sql("""update tabDocPerm set `cancel`=0 where ifnull(`submit`,0)=0""")
frappe.clear_cache()

+ 0
- 23
frappe/patches/v4_0/change_varchar_length.py 查看文件

@@ -1,23 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
for dt in frappe.db.sql_list("""select name from `tabDocType` where ifnull(issingle, 0)=0"""):
desc = dict((d["Field"], d) for d in frappe.db.sql("desc `tab{}`".format(dt), as_dict=True))
alter_table = []

if desc["name"]["Type"] != "varchar(255)":
alter_table.append("change `name` `name` varchar(255) not null")

for fieldname in ("modified_by", "owner", "parent", "parentfield", "parenttype"):
if desc[fieldname]["Type"] != "varchar(255)":
alter_table.append("change `{fieldname}` `{fieldname}` varchar(255)".format(fieldname=fieldname))

if alter_table:
alter_table_query = "alter table `tab{doctype}` {alter_table}".format(doctype=dt, alter_table=",\n".join(alter_table))
# print alter_table_query
frappe.db.sql_ddl(alter_table_query)


+ 0
- 39
frappe/patches/v4_0/create_custom_field_for_owner_match.py 查看文件

@@ -1,39 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field

def execute():
if "match" in frappe.db.get_table_columns("DocPerm"):
create_custom_field_for_owner_match()

def create_custom_field_for_owner_match():
frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1 where `match`='owner'""")

for dt in frappe.db.sql_list("""select distinct parent from `tabDocPerm`
where `match`='owner' and permlevel=0 and parent != 'User'"""):

# a link field pointing to User already exists
if (frappe.db.get_value("DocField", {"parent": dt, "fieldtype": "Link", "options": "User", "default": "__user"})
or frappe.db.get_value("Custom Field", {"dt": dt, "fieldtype": "Link", "options": "User", "default": "__user"})):
print "User link field already exists for", dt
continue

fieldname = "{}_owner".format(frappe.scrub(dt))

create_custom_field(dt, frappe._dict({
"permlevel": 0,
"label": "{} Owner".format(dt),
"fieldname": fieldname,
"fieldtype": "Link",
"options": "User",
"default": "__user"
}))

frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=owner""".format(doctype=dt,
fieldname=fieldname))

# commit is required so that we don't lose these changes because of an error in next loop's ddl
frappe.db.commit()

+ 0
- 10
frappe/patches/v4_0/deprecate_control_panel.py 查看文件

@@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
frappe.db.sql("update `tabDefaultValue` set parenttype='__default' where parenttype='Control Panel'")
frappe.db.sql("update `tabDefaultValue` set parent='__default' where parent='Control Panel'")
frappe.clear_cache()

+ 0
- 13
frappe/patches/v4_0/deprecate_link_selects.py 查看文件

@@ -1,13 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
for name in frappe.db.sql_list("""select name from `tabCustom Field`
where fieldtype="Select" and options like "link:%" """):
custom_field = frappe.get_doc("Custom Field", name)
custom_field.fieldtype = "Link"
custom_field.options = custom_field.options[5:]
custom_field.save()

+ 0
- 14
frappe/patches/v4_0/enable_scheduler_in_system_settings.py 查看文件

@@ -1,14 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils.scheduler import disable_scheduler, enable_scheduler
from frappe.utils import cint

def execute():
frappe.reload_doc("core", "doctype", "system_settings")
if cint(frappe.db.get_global("disable_scheduler")):
disable_scheduler()
else:
enable_scheduler()

+ 0
- 36
frappe/patches/v4_0/file_manager_hooks.py 查看文件

@@ -1,36 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals

import frappe
import os
from frappe.utils import get_files_path
from frappe.utils.file_manager import get_content_hash, get_file


def execute():
frappe.reload_doc('core', 'doctype', 'file_data')
for name, file_name, file_url in frappe.db.sql(
"""select name, file_name, file_url from `tabFile Data`
where file_name is not null"""):
b = frappe.get_doc('File Data', name)
old_file_name = b.file_name
b.file_name = os.path.basename(old_file_name)
if old_file_name.startswith('files/') or old_file_name.startswith('/files/'):
b.file_url = os.path.normpath('/' + old_file_name)
else:
b.file_url = os.path.normpath('/files/' + old_file_name)
try:
_file_name, content = get_file(name)
b.content_hash = get_content_hash(content)
except IOError:
print 'Warning: Error processing ', name
_file_name = old_file_name
b.content_hash = None

try:
b.save()
except frappe.DuplicateEntryError:
frappe.delete_doc(b.doctype, b.name)


+ 0
- 13
frappe/patches/v4_0/fix_attach_field_file_url.py 查看文件

@@ -1,13 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
attach_fields = (frappe.db.sql("""select parent, fieldname from `tabDocField` where fieldtype='Attach'""") +
frappe.db.sql("""select dt, fieldname from `tabCustom Field` where fieldtype='Attach'"""))

for doctype, fieldname in attach_fields:
frappe.db.sql("""update `tab{doctype}` set `{fieldname}`=concat("/", `{fieldname}`)
where `{fieldname}` like 'files/%'""".format(doctype=doctype, fieldname=fieldname))

+ 0
- 11
frappe/patches/v4_0/private_backups.py 查看文件

@@ -1,11 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.installer import make_site_dirs

def execute():
make_site_dirs()
if frappe.local.conf.backup_path and frappe.local.conf.backup_path.startswith("public"):
raise Exception, "Backups path in conf set to public directory"

+ 0
- 4
frappe/patches/v4_0/remove_index_sitemap.py 查看文件

@@ -1,4 +0,0 @@
import frappe

def execute():
pass

+ 0
- 10
frappe/patches/v4_0/remove_old_parent.py 查看文件

@@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
for doctype in frappe.db.sql_list("""select name from `tabDocType` where istable=1"""):
frappe.db.sql("""delete from `tab{0}` where parent like "old_par%:%" """.format(doctype))
frappe.db.sql("""delete from `tabDocField` where parent="0" """)

+ 0
- 10
frappe/patches/v4_0/remove_user_owner_custom_field.py 查看文件

@@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
user_owner = frappe.db.get_value("Custom Field", {"fieldname": "user_owner"})
if user_owner:
frappe.delete_doc("Custom Field", user_owner)

+ 0
- 18
frappe/patches/v4_0/rename_profile_to_user.py 查看文件

@@ -1,18 +0,0 @@
import frappe

from frappe.model import rename_field
from frappe.model.meta import get_table_columns

def execute():
tables = frappe.db.sql_list("show tables")
if "tabUser" not in tables:
frappe.rename_doc("DocType", "Profile", "User", force=True)

if frappe.db.exists("DocType", "Website Route Permission"):
frappe.reload_doc("website", "doctype", "website_route_permission")
if "profile" in get_table_columns("Website Route Permission"):
rename_field("Website Route Permission", "profile", "user")
frappe.reload_doc("website", "doctype", "blogger")

if "profile" in get_table_columns("Blogger"):
rename_field("Blogger", "profile", "user")

+ 0
- 31
frappe/patches/v4_0/rename_sitemap_to_route.py 查看文件

@@ -1,31 +0,0 @@
import frappe

from frappe.model import rename_field

def execute():
tables = frappe.db.sql_list("show tables")
for doctype in ("Website Sitemap", "Website Sitemap Config"):
if "tab{}".format(doctype) in tables:
frappe.delete_doc("DocType", doctype, force=1)
frappe.db.sql("drop table `tab{}`".format(doctype))

if "tabWebsite Route Permission" not in tables:
frappe.rename_doc("DocType", "Website Sitemap Permission", "Website Route Permission", force=True)

for d in ("Blog Category", "Blog Post", "Web Page", "Website Group"):
frappe.reload_doc("website", "doctype", frappe.scrub(d))
rename_field_if_exists(d, "parent_website_sitemap", "parent_website_route")

frappe.reload_doc("website", "doctype", "website_route_permission")

rename_field_if_exists("Website Route Permission", "website_sitemap", "website_route")

for d in ("blog_category", "blog_post", "web_page", "website_group", "post", "user_vote"):
frappe.reload_doc("website", "doctype", d)

def rename_field_if_exists(doctype, old_fieldname, new_fieldname):
try:
rename_field(doctype, old_fieldname, new_fieldname)
except Exception, e:
if e.args[0] != 1054:
raise

+ 0
- 21
frappe/patches/v4_0/replace_deprecated_timezones.py 查看文件

@@ -1,21 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils.momentjs import data as momentjs_data

def execute():
frappe.reload_doc("core", "doctype", "user")

ss = frappe.get_doc("System Settings", "System Settings")
if ss.time_zone in momentjs_data.get("links"):
ss.time_zone = momentjs_data["links"][ss.time_zone]
ss.ignore_mandatory = True
ss.save()

for user, time_zone in frappe.db.sql("select name, time_zone from `tabUser` where ifnull(time_zone, '')!=''"):
if time_zone in momentjs_data.get("links"):
user = frappe.get_doc("User", user)
user.time_zone = momentjs_data["links"][user.time_zone]
user.save()

+ 0
- 10
frappe/patches/v4_0/set_module_in_report.py 查看文件

@@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
frappe.reload_doc("core", "doctype", "report")
frappe.db.sql("""update `tabReport` r set r.module=(select d.module from `tabDocType` d
where d.name=r.ref_doctype) where ifnull(r.module, '')=''""")

+ 0
- 8
frappe/patches/v4_0/set_todo_checked_as_closed.py 查看文件

@@ -1,8 +0,0 @@
import frappe

def execute():
frappe.reload_doc("core", "doctype", "todo")
try:
frappe.db.sql("""update tabToDo set status = if(ifnull(checked,0)=0, 'Open', 'Closed')""")
except:
pass

+ 0
- 11
frappe/patches/v4_0/set_user_gravatar.py 查看文件

@@ -1,11 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
for name in frappe.db.sql_list("select name from `tabUser` where ifnull(user_image, '')=''"):
user = frappe.get_doc("User", name)
user.update_gravatar()
user.db_set("user_image", user.user_image)

+ 0
- 24
frappe/patches/v4_0/set_user_permissions.py 查看文件

@@ -1,24 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
import frappe.permissions

def execute():
frappe.reload_doc("core", "doctype", "docperm")
table_columns = frappe.db.get_table_columns("DocPerm")

if "restricted" in table_columns:
frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1 where ifnull(apply_user_permissions, 0)=0
and restricted=1""")

if "match" in table_columns:
frappe.db.sql("""update `tabDocPerm` set apply_user_permissions=1
where ifnull(apply_user_permissions, 0)=0 and ifnull(`match`, '')!=''""")

# change Restriction to User Permission in tabDefaultValue
frappe.db.sql("""update `tabDefaultValue` set parenttype='User Permission' where parenttype='Restriction'""")

frappe.clear_cache()


+ 0
- 24
frappe/patches/v4_0/set_website_route_idx.py 查看文件

@@ -1,24 +0,0 @@
import frappe

def execute():
pass
# from frappe.website.doctype.website_template.website_template import \
# get_pages_and_generators, get_template_controller
#
# frappe.reload_doc("website", "doctype", "website_template")
# frappe.reload_doc("website", "doctype", "website_route")
#
# for app in frappe.get_installed_apps():
# pages, generators = get_pages_and_generators(app)
# for g in generators:
# doctype = frappe.get_attr(get_template_controller(app, g["path"], g["fname"]) + ".doctype")
# module = frappe.db.get_value("DocType", doctype, "module")
# frappe.reload_doc(frappe.scrub(module), "doctype", frappe.scrub(doctype))
#
# frappe.db.sql("""update `tabBlog Category` set `title`=`name` where ifnull(`title`, '')=''""")
# frappe.db.sql("""update `tabWebsite Route` set idx=null""")
# for doctype in ["Blog Category", "Blog Post", "Web Page", "Website Group"]:
# frappe.db.sql("""update `tab{}` set idx=null""".format(doctype))
#
# from frappe.website.doctype.website_template.website_template import rebuild_website_template
# rebuild_website_template()

+ 0
- 18
frappe/patches/v4_0/update_custom_field_insert_after.py 查看文件

@@ -1,18 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
for d in frappe.db.sql("""select name, dt, insert_after from `tabCustom Field`
where docstatus < 2""", as_dict=1):
dt_meta = frappe.get_meta(d.dt)
if not dt_meta.get_field(d.insert_after):
cf = frappe.get_doc("Custom Field", d.name)
df = dt_meta.get("fields", {"label": d.insert_after})
if df:
cf.insert_after = df[0].fieldname
else:
cf.insert_after = None
cf.save()

+ 0
- 11
frappe/patches/v4_0/update_datetime.py 查看文件

@@ -1,11 +0,0 @@
import frappe

def execute():
for table in frappe.db.sql_list("show tables"):
for field in frappe.db.sql("desc `%s`" % table):
if field[1]=="datetime":
frappe.db.sql("alter table `%s` change `%s` `%s` datetime(6)" % \
(table, field[0], field[0]))
elif field[1]=="time":
frappe.db.sql("alter table `%s` change `%s` `%s` time(6)" % \
(table, field[0], field[0]))

+ 0
- 11
frappe/patches/v4_0/webnotes_to_frappe.py 查看文件

@@ -1,11 +0,0 @@
import frappe, json

def execute():
frappe.clear_cache()
installed = frappe.get_installed_apps()
if "webnotes" in installed:
installed.remove("webnotes")
if "frappe" not in installed:
installed = ["frappe"] + installed
frappe.db.set_global("installed_apps", json.dumps(installed))
frappe.clear_cache()

+ 0
- 21
frappe/patches/v4_0/website_sitemap_hierarchy.py 查看文件

@@ -1,21 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals

import frappe

def execute():
# frappe.db.sql("""update `tabWebsite Route` ws set ref_doctype=(select wsc.ref_doctype
# from `tabWebsite Template` wsc where wsc.name=ws.website_template)
# where ifnull(page_or_generator, '')!='Page'""")

frappe.reload_doc("website", "doctype", "website_settings")

# original_home_page = frappe.db.get_value("Website Settings", "Website Settings", "home_page")
#
# home_page = frappe.db.sql("""select name from `tabWebsite Route`
# where (name=%s or docname=%s) and name!='index'""", (original_home_page, original_home_page))
# home_page = home_page[0][0] if home_page else original_home_page
#
# frappe.db.set_value("Website Settings", "Website Settings", "home_page", home_page)

+ 0
- 0
frappe/patches/v4_1/__init__.py 查看文件


+ 0
- 11
frappe/patches/v4_1/enable_outgoing_email_settings.py 查看文件

@@ -1,11 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
return
# frappe.reload_doc("core", "doctype", "outgoing_email_settings")
# if (frappe.db.get_value("Outgoing Email Settings", "Outgoing Email Settings", "mail_server") or "").strip():
# frappe.db.set_value("Outgoing Email Settings", "Outgoing Email Settings", "enabled", 1)

+ 0
- 24
frappe/patches/v4_1/enable_print_as_pdf.py 查看文件

@@ -1,24 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
frappe.reload_doc("core", "doctype", "print_settings")
print_settings = frappe.get_doc("Print Settings")
print_settings.print_style = "Modern"

try:
import pdfkit
except ImportError:
pass
else:
# if someone has already configured in Outgoing Email Settings
# outgoing_email_settings = frappe.db.get_singles_dict("Outgoing Email Settings")
# if "send_print_as_pdf" in outgoing_email_settings:
# print_settings.send_print_as_pdf = outgoing_email_settings.send_print_as_pdf
# print_settings.pdf_page_size = outgoing_email_settings.pdf_page_size

print_settings.send_print_as_pdf = 1
print_settings.save()

+ 0
- 98
frappe/patches/v4_1/file_manager_fix.py 查看文件

@@ -1,98 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals

import frappe
import os
from frappe.utils.file_manager import get_content_hash, get_file, get_file_name
from frappe.utils import get_files_path, get_site_path

# The files missed by the previous patch might have been replaced with new files
# with the same filename
#
# This patch does the following,
# * Detect which files were replaced and rename them with name{hash:5}.extn and
# update filedata record for the new file
#
# * make missing_files.txt in site dir with files that should be recovered from
# a backup from a time before version 3 migration
#
# * Patch remaining unpatched file data records.

def execute():
frappe.db.auto_commit_on_many_writes = True
rename_replacing_files()
for name, file_name, file_url in frappe.db.sql(
"""select name, file_name, file_url from `tabFile Data`
where ifnull(file_name, '')!='' and ifnull(content_hash, '')=''"""):
b = frappe.get_doc('File Data', name)
old_file_name = b.file_name
b.file_name = os.path.basename(old_file_name)
if old_file_name.startswith('files/') or old_file_name.startswith('/files/'):
b.file_url = os.path.normpath('/' + old_file_name)
else:
b.file_url = os.path.normpath('/files/' + old_file_name)
try:
_file_name, content = get_file(name)
b.content_hash = get_content_hash(content)
except IOError:
print 'Warning: Error processing ', name
b.content_hash = None
b.ignore_duplicate_entry_error = True
b.save()
frappe.db.auto_commit_on_many_writes = False

def get_replaced_files():
ret = []
new_files = dict(frappe.db.sql("select name, file_name from `tabFile Data` where file_name not like 'files/%'"))
old_files = dict(frappe.db.sql("select name, file_name from `tabFile Data` where ifnull(content_hash, '')=''"))
invfiles = invert_dict(new_files)

for nname, nfilename in new_files.iteritems():
if 'files/' + nfilename in old_files.values():
ret.append((nfilename, invfiles[nfilename]))
return ret

def rename_replacing_files():
replaced_files = get_replaced_files()
if len(replaced_files):
missing_files = [v[0] for v in replaced_files]
with open(get_site_path('missing_files.txt'), 'w') as f:
f.write(('\n'.join(missing_files) + '\n').encode('utf-8'))

for file_name, file_datas in replaced_files:
print 'processing ' + file_name
content_hash = frappe.db.get_value('File Data', file_datas[0], 'content_hash')
if not content_hash:
continue
new_file_name = get_file_name(file_name, content_hash)
if os.path.exists(get_files_path(new_file_name)):
continue
print 'skipping ' + file_name
try:
os.rename(get_files_path(file_name), get_files_path(new_file_name))
except OSError:
print 'Error renaming ', file_name
for name in file_datas:
f = frappe.get_doc('File Data', name)
f.file_name = new_file_name
f.file_url = '/files/' + new_file_name
f.save()

def invert_dict(ddict):
ret = {}
for k,v in ddict.iteritems():
if not ret.get(v):
ret[v] = [k]
else:
ret[v].append(k)
return ret

def get_file_name(fname, hash):
if '.' in fname:
partial, extn = fname.rsplit('.', 1)
else:
partial = fname
extn = ''
return '{partial}{suffix}.{extn}'.format(partial=partial, extn=extn, suffix=hash[:5])

+ 0
- 0
frappe/patches/v4_2/__init__.py 查看文件


+ 0
- 11
frappe/patches/v4_2/print_with_letterhead.py 查看文件

@@ -1,11 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def execute():
frappe.reload_doc("core", "doctype", "print_settings")
print_settings = frappe.get_doc("Print Settings")
print_settings.with_letterhead = 1
print_settings.save()

+ 0
- 7
frappe/patches/v4_2/refactor_website_routing.py 查看文件

@@ -1,7 +0,0 @@
import frappe

def execute():
# clear all static web pages
frappe.delete_doc("DocType", "Website Route", force=1)
frappe.delete_doc("Page", "sitemap-browser", force=1)
frappe.db.sql("drop table if exists `tabWebsite Route`")

+ 0
- 10
frappe/patches/v4_2/set_assign_in_doc.py 查看文件

@@ -1,10 +0,0 @@
import frappe

def execute():
for name in frappe.db.sql_list("""select name from `tabToDo`
where ifnull(reference_type, '')!='' and ifnull(reference_name, '')!=''"""):
try:
frappe.get_doc("ToDo", name).on_update()
except Exception, e:
if e.args[0]!=1146:
raise

+ 7
- 0
frappe/patches/v5_0/clear_website_group.py 查看文件

@@ -0,0 +1,7 @@
import frappe

def execute():
frappe.delete_doc("DocType", "Post")
frappe.delete_doc("DocType", "Website Group")
frappe.delete_doc("DocType", "Website Route Permission")
frappe.delete_doc("DocType", "User Vote")

+ 0
- 0
frappe/templates/website_group/__init__.py 查看文件


+ 0
- 19
frappe/templates/website_group/edit_post.html 查看文件

@@ -1,19 +0,0 @@
{% include "templates/includes/post_editor.html" %}

<script>
frappe.require("/assets/js/canvasResize.min.js");
$(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
- 27
frappe/templates/website_group/forum.html 查看文件

@@ -1,27 +0,0 @@
<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) {
frappe.setup_pagination();
}
{% if group.group_type == "Forum" -%}
website.toggle_edit(true);

{% elif group.group_type == "Tasks" %}
website.toggle_edit();

{% elif group.group_type == "Events" %}
website.toggle_edit();
website.format_event_timestamps();

{%- endif %}
});
</script>

+ 0
- 64
frappe/templates/website_group/forum.py 查看文件

@@ -1,64 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.utils import now_datetime, get_datetime_str
from frappe.website.permissions import get_access

@frappe.whitelist(allow_guest=True)
def get_post_list_html(group, view, limit_start=0, limit_length=20):
from frappe.website.doctype.website_group.website_group import get_views

# verify permission for paging
if frappe.local.form_dict.cmd == "get_post_list_html":
doc = frappe.get_doc("Website Group", group)
access = get_access(doc, doc.get_route())

if not access.get("read"):
return frappe.PermissionError

conditions = ""
values = [group]

group_type = frappe.db.get_value("Website Group", group, "group_type")
if group_type == "Events":
# should show based on time upto precision of hour
# because the current hour should also be in upcoming
values.append(now_datetime().replace(minute=0, second=0, microsecond=0))

if view in ("feed", "closed"):
order_by = "p.creation desc"

if view == "closed":
conditions += " and p.is_task=1 and p.status='Closed'"

elif view in ("popular", "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)

if view == "open":
conditions += " and p.is_task=1 and p.status='Open'"

elif view == "upcoming":
conditions += " and p.is_event=1 and p.event_datetime >= %s"
order_by = "p.event_datetime asc"

elif view == "past":
conditions += " and p.is_event=1 and p.event_datetime < %s"
order_by = "p.event_datetime desc"

values += [int(limit_start), int(limit_length)]

posts = frappe.db.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, `tabUser` pr
where p.website_group = %s and pr.name = p.owner and ifnull(p.parent_post, '')=''
{conditions} order by {order_by} limit %s, %s""".format(conditions=conditions, order_by=order_by),
tuple(values), as_dict=True)

context = { "posts": posts, "limit_start": limit_start, "view": get_views(group_type)[view] }

return frappe.get_template("templates/includes/post_list.html").render(context)


+ 0
- 33
frappe/templates/website_group/post.html 查看文件

@@ -1,33 +0,0 @@
<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>
frappe.require("/assets/js/canvasResize.min.js");
$(function() {
website.toggle_edit(true);
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
- 156
frappe/templates/website_group/post.py 查看文件

@@ -1,156 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import get_fullname
from frappe.website.permissions import get_access
from frappe.utils.file_manager import save_file

def get_post_context(context):
post = frappe.get_doc("Post", frappe.form_dict.name)
if post.parent_post:
raise frappe.PermissionError

def _get_post_context():
fullname = get_fullname(post.owner)
return {
"title": "{} by {}".format(post.title, fullname),
"parent_post_html": get_parent_post_html(post, context),
"post_list_html": get_child_posts_html(post, context),
"parent_post": post.name
}

cache_key = "website_group_post:{}".format(post.name)
return frappe.cache().get_value(cache_key, lambda: _get_post_context())

def get_parent_post_html(post, context):
user = frappe.get_doc("User", post.owner)
for fieldname in ("first_name", "last_name", "user_image", "location"):
post.set(fieldname, user.get(fieldname))

return frappe.get_template("templates/includes/inline_post.html")\
.render({"post": post, "view": context.view})

def get_child_posts_html(post, context):
posts = frappe.db.sql("""select p.*, pr.user_image, pr.first_name, pr.last_name
from tabPost p, tabUser pr
where p.parent_post=%s and pr.name = p.owner
order by p.creation asc""", (post.name,), as_dict=True)

return frappe.get_template("templates/includes/post_list.html")\
.render({
"posts": posts,
"parent_post": post.name,
"view": context.view
})

def clear_post_cache(post=None):
cache = frappe.cache()
posts = [post] if post else frappe.db.sql_list("select name from `tabPost`")

for post in posts:
cache.delete_value("website_group_post:{}".format(post))

@frappe.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):

doc = frappe.get_doc("Website Group", group)
access = get_access(doc, doc.get_route())
if not access.get("write"):
raise frappe.PermissionError

if parent_post:
if frappe.db.get_value("Post", parent_post, "parent_post"):
frappe.throw(_("Cannot reply to a reply"))

group = frappe.get_doc("Website Group", group)
post = frappe.get_doc({
"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.is_task = 1
post.assigned_to = assigned_to
elif group.group_type == "Events":
post.is_event = 1
post.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.parent_post or post.name

@frappe.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 = frappe.get_doc("Post", post)
group = frappe.get_doc("Website Group", post.website_group)
access = get_access(group, group.get_route())

if not access.get("write"):
raise frappe.PermissionError

# TODO improve error message
if frappe.session.user != post.owner:
for fieldname in ("title", "content"):
if post.get(fieldname) != locals().get(fieldname):
frappe.throw(_("Cannot change {0}").format(fieldname))

if picture and picture_name:
frappe.throw(_("Cannot change picture"))

post.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.parent_post or post.name

def process_picture(post, picture_name, picture):
from frappe.website.doctype.website_group.website_group import clear_cache

post.picture_url = save_file(picture_name, picture, "Post", post.name, decode=True).file_url
frappe.db.set_value("Post", post.name, "picture_url", post.picture_url)
clear_cache(website_group=post.website_group)

@frappe.whitelist()
def suggest_user(group, term):
"""suggest a user that has read permission in this group tree"""
users = frappe.db.sql("""select
pr.name, pr.first_name, pr.last_name,
pr.user_image, pr.location
from `tabUser` pr
where (pr.first_name like %(term)s or pr.last_name like %(term)s)
and pr.user_type = 'Website User' and pr.enabled=1""",
{"term": "%{}%".format(term), "group": group}, as_dict=True)

template = frappe.get_template("templates/includes/user_display.html")
return [{
"value": "{} {}".format(pr.first_name or "", pr.last_name or "").strip(),
"user_html": template.render({"user": pr}),
"user": pr.name
} for pr in users]

+ 0
- 77
frappe/templates/website_group/settings.html 查看文件

@@ -1,77 +0,0 @@
<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 user in users %}
{% include "templates/includes/sitemap_permission.html" %}
{% endfor %}
</tbody>
</table>
</div>
</div>

<script>
$(function() {
website.setup_settings();
})
</script>

+ 0
- 104
frappe/templates/website_group/settings.py 查看文件

@@ -1,104 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.website.permissions import get_access
from frappe.email.bulk import send

@frappe.whitelist()
def suggest_user(term, group):
doc = frappe.get_doc("Website Group", group)
pathname = doc.get_route()
if not get_access(doc, pathname).get("admin"):
raise frappe.PermissionError

users = frappe.db.sql("""select pr.name, pr.first_name, pr.last_name,
pr.user_image, pr.location
from `tabUser` pr
where (pr.first_name like %(term)s or pr.last_name like %(term)s)
and pr.user_type = "Website User"
and pr.user_image is not null and pr.enabled=1
and not exists(select wsp.name from `tabWebsite Route Permission` wsp
where wsp.website_route=%(group)s and wsp.user=pr.name)""",
{"term": "%{}%".format(term), "group": pathname}, as_dict=True)

template = frappe.get_template("templates/includes/user_display.html")
return [{
"value": "{} {}".format(pr.first_name or "", pr.last_name or ""),
"user_html": template.render({"user": pr}),
"user": pr.name
} for pr in users]

@frappe.whitelist()
def add_sitemap_permission(group, user):
doc = frappe.get_doc("Website Group", group)
pathname = doc.get_route()
if not get_access(doc, pathname).get("admin"):
raise frappe.PermissionError

permission = frappe.get_doc({
"doctype": "Website Route Permission",
"website_route": pathname,
"user": user,
"read": 1
})
permission.insert(ignore_permissions=True)

user = permission.as_dict()
user.update(frappe.db.get_value("User", user.user,
["name", "first_name", "last_name", "user_image", "location"], as_dict=True))

return frappe.get_template("templates/includes/sitemap_permission.html").render({
"user": user
})

@frappe.whitelist()
def update_permission(group, user, perm, value):
doc = frappe.get_doc("Website Group", group)
pathname = doc.get_route()
if not get_access(doc, pathname).get("admin"):
raise frappe.PermissionError

permission = frappe.get_doc("Website Route Permission",
{"website_route": pathname, "user": user, "reference": group})
permission.set(perm, int(value))
permission.save(ignore_permissions=True)

# send email
if perm=="admin" and int(value):
subject = "You have been made Administrator of Group " + doc.group_title

send(recipients=[user],
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)

@frappe.whitelist()
def update_description(group, description):
doc = frappe.get_doc("Website Group", group)
pathname = doc.get_route()
if not get_access(doc, pathname).get("admin"):
raise frappe.PermissionError

group = frappe.get_doc("Website Group", group)
group.group_description = description
group.save(ignore_permissions=True)

@frappe.whitelist()
def add_website_group(group, new_group, public_read, public_write, group_type="Forum"):
doc = frappe.get_doc("Website Group", group)
pathname = doc.get_route()
if not get_access(doc, pathname).get("admin"):
raise frappe.PermissionError

frappe.get_doc({
"doctype": "Website Group",
"group_name": group + "-" + new_group,
"group_title": new_group,
"parent_website_group": group,
"group_type": group_type,
"public_read": int(public_read),
"public_write": int(public_write)
}).insert(ignore_permissions=True)

+ 1
- 5
frappe/website/context.py 查看文件

@@ -8,7 +8,6 @@ from frappe.website.doctype.website_settings.website_settings import get_website
from frappe.website.template import render_blocks
from frappe.website.router import get_route_info
from frappe.website.utils import can_cache
from frappe.website.permissions import get_access

def get_context(path):
context = None
@@ -28,10 +27,7 @@ def get_context(path):
context = get_route_info(path)

# permission may be required for rendering
if context.doc and context.doc.doctype=="Website Group":
context["access"] = get_access(context.doc, context.pathname)
else:
context["access"] = frappe._dict({"public_read":1, "public_write":1})
context["access"] = frappe._dict({"public_read":1, "public_write":1})

context = build_context(context)
add_data_path(context)


+ 0
- 0
frappe/website/doctype/post/__init__.py 查看文件


+ 0
- 128
frappe/website/doctype/post/post.json 查看文件

@@ -1,128 +0,0 @@
{
"autoname": "P.#######",
"creation": "2014-01-07 14:00:04.000000",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Transaction",
"fields": [
{
"fieldname": "title",
"fieldtype": "Data",
"label": "Title",
"permlevel": 0,
"reqd": 0
},
{
"fieldname": "content",
"fieldtype": "Text",
"in_list_view": 1,
"label": "Content",
"permlevel": 0,
"reqd": 1
},
{
"fieldname": "picture_url",
"fieldtype": "Attach",
"label": "Picture URL",
"permlevel": 0
},
{
"fieldname": "website_group",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Website Group",
"options": "Website Group",
"permlevel": 0,
"reqd": 1,
"search_index": 1
},
{
"fieldname": "is_event",
"fieldtype": "Check",
"label": "Is Event",
"permlevel": 0
},
{
"fieldname": "event_datetime",
"fieldtype": "Datetime",
"label": "Event Datetime",
"permlevel": 0
},
{
"fieldname": "is_task",
"fieldtype": "Check",
"label": "Is Task",
"permlevel": 0
},
{
"fieldname": "assigned_to",
"fieldtype": "Link",
"label": "Assigned To",
"options": "User",
"permlevel": 0
},
{
"fieldname": "assigned_to_fullname",
"fieldtype": "Data",
"label": "Assigned To Fullname",
"permlevel": 0
},
{
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "\nOpen\nClosed",
"permlevel": 0,
"reqd": 0
},
{
"fieldname": "parent_post",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Parent Post",
"options": "Post",
"permlevel": 0,
"search_index": 1
},
{
"fieldname": "unsubscribe",
"fieldtype": "Check",
"label": "Unsubscribe",
"permlevel": 0
},
{
"default": "0",
"fieldname": "upvotes",
"fieldtype": "Int",
"label": "Upvotes",
"permlevel": 0
},
{
"default": "0",
"fieldname": "replies",
"fieldtype": "Int",
"label": "Replies",
"permlevel": 0
}
],
"icon": "icon-comment",
"idx": 1,
"modified": "2014-03-03 14:53:19.000000",
"modified_by": "Administrator",
"module": "Website",
"name": "Post",
"owner": "Administrator",
"permissions": [
{
"cancel": 0,
"create": 1,
"delete": 1,
"export": 1,
"permlevel": 0,
"read": 1,
"report": 1,
"role": "System Manager",
"write": 1
}
]
}

+ 0
- 99
frappe/website/doctype/post/post.py 查看文件

@@ -1,99 +0,0 @@
# 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 frappe
from frappe import _
from frappe.utils import get_fullname
from frappe.email.bulk import send

from frappe.model.document import Document

class Post(Document):

def validate(self):
if not self.parent_post and not self.title:
frappe.throw(_("Title is required"))

self.assigned_to = frappe.db.get_value(self.doctype, self.name, "assigned_to")
if self.is_task:
if not self.status:
self.status = "Open"
if self.assigned_to:
if not self.assigned_to_fullname:
self.assigned_to_fullname = get_fullname(self.assigned_to)
else:
self.assigned_to_fullname = None
else:
self.assigned_to = self.assigned_to_fullname = self.status = None

if self.is_event:
if not self.event_datetime:
frappe.throw(_("Please specify Event date and time"))
else:
self.event_datetime = None

def on_update(self):
from frappe.templates.website_group.post import clear_post_cache
from frappe.website.doctype.website_group.website_group import clear_cache

clear_cache(website_group=self.website_group)
clear_post_cache(self.parent_post or self.name)

if self.assigned_to and self.assigned_to != self.assigned_to \
and frappe.session.user != self.assigned_to:

# send assignment email
frappe.sendmail(recipients=[self.assigned_to],
subject="You have been assigned this Task by {}".format(get_fullname(self.modified_by)),
content=self.get_reply_email_message(self.name, get_fullname(self.owner)))

def send_email_on_reply(self):
owner_fullname = get_fullname(self.owner)

parent_post = frappe.get_doc("Post", self.parent_post)

message = self.get_reply_email_message(self.name, owner_fullname)

# send email to the owner of the post, if he/she is different
if parent_post.owner != self.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.doctype, ref_docname=self.name)

# send email to members who part of the conversation
participants = frappe.db.sql("""select owner, name from `tabPost`
where parent_post=%s and owner not in (%s, %s) order by creation asc""",
(self.parent_post, parent_post.owner, self.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.doctype, ref_docname=self.name)

def get_reply_email_message(self, post_name, owner_fullname=None):
message = self.content
if self.picture_url:
message += """<div><img src="{url}" style="max-width: 100%"></div>"""\
.format(url=self.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

+ 0
- 0
frappe/website/doctype/user_vote/__init__.py 查看文件


+ 0
- 43
frappe/website/doctype/user_vote/user_vote.json 查看文件

@@ -1,43 +0,0 @@
{
"autoname": "_VOTE.#######",
"creation": "2014-01-17 16:26:21.000000",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Transaction",
"fields": [
{
"fieldname": "ref_doctype",
"fieldtype": "Link",
"label": "Ref DocType",
"options": "DocType",
"permlevel": 0,
"search_index": 0
},
{
"fieldname": "ref_name",
"fieldtype": "Data",
"label": "Ref Name",
"permlevel": 0,
"search_index": 0
}
],
"idx": 1,
"modified": "2014-01-21 15:45:30.000000",
"modified_by": "Administrator",
"module": "Website",
"name": "User Vote",
"owner": "Administrator",
"permissions": [
{
"cancel": 0,
"create": 1,
"delete": 1,
"export": 1,
"permlevel": 0,
"read": 1,
"report": 1,
"role": "System Manager",
"write": 1
}
]
}

+ 0
- 55
frappe/website/doctype/user_vote/user_vote.py 查看文件

@@ -1,55 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.website.permissions import get_access
from frappe.website.doctype.website_group.website_group import clear_cache
from frappe.model.document import Document

class UserVote(Document):
def after_insert(self):
clear_cache(self.ref_name)

def validate(self):
# if new
if self.get("__islocal"):
if frappe.db.get_value("User Vote", {"ref_doctype": self.ref_doctype,
"ref_name": self.ref_name, "owner": frappe.session.user}):

raise frappe.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 = frappe.db.sql("""select count(*) from `tabUser Vote` where ref_doctype=%s and ref_name=%s""",
(self.ref_doctype, self.ref_name))[0][0]
frappe.db.set_value(self.ref_doctype, self.ref_name, "upvotes", count + cnt)

def on_doctype_update():
frappe.db.add_index("User Vote", ["ref_doctype", "ref_name"])

# don't allow guest to give vote
@frappe.whitelist()
def set_vote(ref_doctype, ref_name):
website_group_name = frappe.db.get_value(ref_doctype, ref_name, "website_group")
group = frappe.get_doc("Website Group", website_group_name)

if not get_access(group, group.get_route()).get("read"):
raise frappe.PermissionError

try:
user_vote = frappe.get_doc({
"doctype": "User Vote",
"ref_doctype": ref_doctype,
"ref_name": ref_name
})
user_vote.ignore_permissions = True
user_vote.insert()
return "ok"
except frappe.DuplicateEntryError:
return "duplicate"

+ 0
- 0
frappe/website/doctype/website_group/__init__.py 查看文件


+ 0
- 7
frappe/website/doctype/website_group/test_records.json 查看文件

@@ -1,7 +0,0 @@
[
{
"doctype": "Website Group",
"group_name": "_Test Website Group 1",
"group_title": "_Test Website Group 1"
}
]

+ 0
- 10
frappe/website/doctype/website_group/test_website_group.py 查看文件

@@ -1,10 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# See license.txt

import frappe
import unittest

test_records = frappe.get_test_records('Website Group')

class TestWebsiteGroup(unittest.TestCase):
pass

+ 0
- 153
frappe/website/doctype/website_group/website_group.json 查看文件

@@ -1,153 +0,0 @@
{
"creation": "2014-01-29 15:57:42",
"docstatus": 0,
"doctype": "DocType",
"document_type": "Master",
"fields": [
{
"fieldname": "name_and_description",
"fieldtype": "Section Break",
"label": "Name and Description",
"permlevel": 0
},
{
"fieldname": "group_name",
"fieldtype": "Data",
"label": "Group Name",
"permlevel": 0,
"reqd": 1
},
{
"fieldname": "group_title",
"fieldtype": "Data",
"label": "Group Title",
"no_copy": 0,
"permlevel": 0,
"reqd": 1
},
{
"fieldname": "group_type",
"fieldtype": "Select",
"label": "Group Type",
"options": "Forum\nTasks\nEvents",
"permlevel": 0,
"reqd": 1
},
{
"fieldname": "parent_website_group",
"fieldtype": "Link",
"label": "Parent Website Group",
"options": "Website Group",
"permlevel": 0
},
{
"description": "Display in the sidebar of this Website Route node",
"fieldname": "parent_website_route",
"fieldtype": "Read Only",
"in_list_view": 0,
"label": "Parent Website Route",
"options": "",
"permlevel": 0
},
{
"fieldname": "column_break_6",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "group_description",
"fieldtype": "Text",
"label": "Group Description",
"permlevel": 0
},
{
"fieldname": "page_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Page Name",
"no_copy": 1,
"permlevel": 0,
"reqd": 0
},
{
"fieldname": "details",
"fieldtype": "Section Break",
"label": "Details",
"permlevel": 0
},
{
"fieldname": "public_read",
"fieldtype": "Check",
"label": "Anyone Can Read",
"permlevel": 0
},
{
"fieldname": "public_write",
"fieldtype": "Check",
"label": "Anyone Can Write",
"permlevel": 0
},
{
"fieldname": "column_break_12",
"fieldtype": "Column Break",
"permlevel": 0
},
{
"fieldname": "upvotes",
"fieldtype": "Int",
"label": "Upvotes",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "replies",
"fieldtype": "Int",
"label": "Replies",
"permlevel": 0,
"read_only": 1
},
{
"fieldname": "lft",
"fieldtype": "Int",
"hidden": 1,
"label": "lft",
"permlevel": 0
},
{
"fieldname": "rgt",
"fieldtype": "Int",
"hidden": 1,
"label": "rgt",
"permlevel": 0
},
{
"fieldname": "old_parent",
"fieldtype": "Read Only",
"hidden": 1,
"label": "Old Parent",
"permlevel": 0
}
],
"icon": "icon-group",
"idx": 1,
"modified": "2014-08-19 14:33:40.664635",
"modified_by": "Administrator",
"module": "Website",
"name": "Website Group",
"owner": "Administrator",
"permissions": [
{
"cancel": 0,
"create": 1,
"delete": 1,
"export": 1,
"permlevel": 0,
"read": 1,
"report": 1,
"role": "Website Manager",
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC"
}

+ 0
- 251
frappe/website/doctype/website_group/website_group.py 查看文件

@@ -1,251 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe
from frappe.website.website_generator import WebsiteGenerator
from frappe.website.render import can_cache
from frappe.templates.website_group.forum import get_post_list_html
from frappe.utils.nestedset import NestedSet

class WebsiteGroup(WebsiteGenerator, NestedSet):
no_cache = True
template = "templates/generators/website_group.html"
parent_website_route_field = "parent_website_group"
page_title_field = "group_title"

def on_update(self):
WebsiteGenerator.on_update(self)
NestedSet.on_update(self)
clear_cache(website_group=self.name)

def on_trash(self):
WebsiteGenerator.on_trash(self)
NestedSet.on_trash(self)

def after_insert(self):
clear_cache(website_group=self.name)

def get_context(self, context):
group, view = guess_group_view(context)

try:
if not has_access(context.access, view):
raise frappe.PermissionError

return get_group_context(group, view, context)

except frappe.DoesNotExistError:
return {
"content": '<div class="alert alert-danger full-page">'
'The page you are looking for does not exist.</div>'
}
except frappe.PermissionError:
return {
"content": '<div class="alert alert-danger full-page">'
'You are not permitted to view this page.</div>'
}

return context


def get_group_context(group, view, context):
cache_key = "website_group_context:{}:{}".format(group, view)

views = get_views(context.doc.group_type)
view = frappe._dict(views.get(view))

if can_cache(view.no_cache):
group_context = frappe.cache().get_value(cache_key)
if group_context:
return group_context

group_context = build_group_context(group, view, views, context)

if can_cache(view.get("no_cache")):
frappe.cache().set_value(cache_key, group_context)

group_context.children = context.doc.get_children()

return group_context

def build_group_context(group, view, views, context):
title = "{} - {}".format(context.doc.group_title, view.get("label"))

group_context = frappe._dict({
"group": context.doc,
"view": view,
"views": [v[1] for v in sorted(views.iteritems(), key=lambda (k, v): v.get("idx"))],
"title": title,
"pathname": context.pathname
})
group_context.update(build_view_context(group_context))

return group_context

def build_view_context(context):
from frappe.templates.website_group.post import get_post_context

if context.view.name in ("popular", "feed", "open", "closed", "upcoming", "past"):
context.post_list_html = get_post_list_html(context.group.name, context.view.name)

elif context.view.name == "edit":
context.post = frappe.get_doc("Post", frappe.form_dict.name).as_dict()

if context.post.assigned_to:
context.user = frappe.get_doc("User", context.post.assigned_to)

elif context.view.name == "settings":
context.users = frappe.db.sql("""select p.*, wsp.`read`, wsp.`write`, wsp.`admin`
from `tabUser` p, `tabWebsite Route Permission` wsp
where wsp.website_route=%s and wsp.user=p.name""", context.pathname, as_dict=True)

elif context.view.name == "post":
context.update(get_post_context(context))

return context

def guess_group_view(context):
group = context.docname
view = frappe.form_dict.view or get_default_view(context.doc.group_type)
return group, view

def get_default_view(group_type):
for view, opts in get_views(group_type).iteritems():
if opts.get("default"):
return view

def get_views(group_type=None):
if group_type:
group_views = frappe._dict(views[group_type])
else:
group_views = {}
for group_type in views:
group_views.update(views[group_type].copy())

group_views.update(common_views)

if group_type == "Forum":
group_views["post"]["upvote"] = True

return group_views

def has_access(access, view):
if view=="settings":
return access.get("admin")
elif view in ("add", "edit"):
return access.get("write")
else:
return access.get("read")

def clear_cache(website_group=None):
from frappe.templates.website_group.post import clear_post_cache
if website_group:
website_groups = [website_group]
else:
clear_post_cache()
website_groups = frappe.db.sql_list("""select name from `tabWebsite Group`""")

cache = frappe.cache()
all_views = get_views()
for group in website_groups:
for view in all_views:
cache.delete_value("website_group_context:{}:{}".format(group, view))

def clear_event_cache():
for group in frappe.db.sql_list("""select name from `tabWebsite Group` where group_type='Event'"""):
clear_cache(website_group=group)

views = {
"Forum": {
"popular": {
"name": "popular",
"template_path": "templates/website_group/forum.html",
"label": "Popular",
"icon": "icon-heart",
"default": True,
"upvote": True,
"idx": 1
},
"feed": {
"name": "feed",
"template_path": "templates/website_group/forum.html",
"label": "Feed",
"icon": "icon-rss",
"upvote": True,
"idx": 2
}
},
"Tasks": {
"open": {
"name": "open",
"template_path": "templates/website_group/forum.html",
"label": "Open",
"icon": "icon-inbox",
"default": True,
"upvote": True,
"idx": 1
},
"closed": {
"name": "closed",
"template_path": "templates/website_group/forum.html",
"label": "Closed",
"icon": "icon-smile",
"idx": 2
}
},
"Events": {
"upcoming": {
"name": "upcoming",
"template_path": "templates/website_group/forum.html",
"label": "Upcoming",
"icon": "icon-calendar",
"default": True,
"idx": 1
},
"past": {
"name": "past",
"template_path": "templates/website_group/forum.html",
"label": "Past",
"icon": "icon-time",
"idx": 2
}
}
}

common_views = {
"post": {
"name": "post",
"template_path": "templates/website_group/post.html",
"label": "Post",
"icon": "icon-comments",
"hidden": True,
"no_cache": True,
"idx": 3
},
"edit": {
"name": "edit",
"template_path": "templates/website_group/edit_post.html",
"label": "Edit Post",
"icon": "icon-pencil",
"hidden": True,
"no_cache": True,
"idx": 4
},
"add": {
"name": "add",
"template_path": "templates/website_group/edit_post.html",
"label": "Add Post",
"icon": "icon-plus",
"hidden": True,
"idx": 5
},
"settings": {
"name": "settings",
"template_path": "templates/website_group/settings.html",
"label": "Settings",
"icon": "icon-cog",
"hidden": True,
"idx": 6
}
}

+ 0
- 0
frappe/website/doctype/website_route_permission/__init__.py 查看文件


+ 0
- 79
frappe/website/doctype/website_route_permission/website_route_permission.json 查看文件

@@ -1,79 +0,0 @@
{
"autoname": "WSP.######",
"creation": "2014-01-29 17:56:29",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"fieldname": "website_route",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Website Route",
"options": "",
"permlevel": 0,
"reqd": 1,
"search_index": 1
},
{
"fieldname": "user",
"fieldtype": "Link",
"in_list_view": 1,
"label": "User",
"options": "User",
"permlevel": 0,
"reqd": 1,
"search_index": 1
},
{
"fieldname": "read",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Read",
"permlevel": 0
},
{
"fieldname": "write",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Write",
"permlevel": 0
},
{
"fieldname": "admin",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Admin",
"permlevel": 0
},
{
"fieldname": "reference",
"fieldtype": "Link",
"label": "reference",
"options": "Website Group",
"permlevel": 0
}
],
"icon": "icon-shield",
"idx": 1,
"modified": "2014-08-20 12:56:15.141568",
"modified_by": "Administrator",
"module": "Website",
"name": "Website Route Permission",
"owner": "Administrator",
"permissions": [
{
"cancel": 0,
"create": 1,
"delete": 0,
"export": 1,
"import": 0,
"permlevel": 0,
"read": 1,
"report": 1,
"role": "Website Manager",
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC"
}

+ 0
- 16
frappe/website/doctype/website_route_permission/website_route_permission.py 查看文件

@@ -1,16 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

from frappe.website.permissions import remove_empty_permissions, clear_permissions

from frappe.model.document import Document

class WebsiteRoutePermission(Document):
def on_update(self):
remove_empty_permissions()
clear_permissions(self.user)

+ 0
- 564
frappe/website/js/website_group.js 查看文件

@@ -1,564 +0,0 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.provide("website");
$.extend(website, {
toggle_permitted: function() {
if(website.access) {
// hide certain views
$('li[data-view="add"]').toggleClass("hide", !website.access.write);
$('li[data-view="settings"]').toggleClass("hide", !website.access.admin);
$('li[data-view="edit"]').toggleClass("hide", website.view!=="edit");
// show message
if(!website.access.write) {
var sid = frappe.get_cookie("sid");
if(!sid || sid==="Guest") {
$(".post-list-help").html("Please login to post");
} else {
$(".post-list-help").html("You do not have permission to post");
}
} else {
$(".post-list-help").html("");
}
}
},
setup_pagination: function() {
var $btn = $(".btn-more")
.removeClass("hide")
.on("click", function() {
frappe.call({
btn: $btn,
type: "GET",
args: {
cmd: "frappe.templates.website_group.forum.get_post_list_html",
limit_start: $(".post").length,
limit_length: 20,
group: website.group,
view: website.view,
pathname: website.pathname
},
callback: function(data) {
$(".post-list").append(data.message);
$btn.toggleClass("hide", !(data.message && data.message.length===opts.args.limit_length));
website.toggle_upvote();
}
})
});
},
bind_add_post: function() {
$(".btn-post-add").on("click", website.add_post);

$pic_input = $(".control-post-add-picture").on("change", website.add_picture);
$(".btn-post-add-picture").on("click", function() {
$pic_input.click();
});
},
add_post: function() {
if(website.post) {
frappe.msgprint(__("Post already exists. Cannot add again!"));
return;
}
website._update_post(this, "frappe.templates.website_group.post.add_post");
},
bind_save_post: function() {
$(".btn-post-add").addClass("hide");
$(".btn-post-save").removeClass("hide").on("click", website.save_post);
$(".post-picture").toggleClass("hide", !$(".post-picture").attr("src"));
},
save_post: function() {
if(!website.post) {
frappe.msgprint(__("Post does not exist. Please add post!"));
return;
}
website._update_post(this, "frappe.templates.website_group.post.save_post");
},
_update_post: function(btn, cmd) {
var values = website.get_editor_values();
if(!values) {
return;
}
frappe.call({
btn: btn,
type: "POST",
args: $.extend({
cmd: cmd,
group: website.group,
post: website.post || undefined,
}, values),
callback: function(data) {
var url = window.location.pathname + "?view=post&name=" + data.message;
window.location.href = url;
}
});
},
get_editor_values: function() {
var values = {};
$.each($('.post-editor [data-fieldname]'), function(i, ele) {
var $ele = $(ele);
values[$ele.attr("data-fieldname")] = $ele.val();
});
values.parent_post = $(".post-editor").attr("data-parent-post");
values.picture_name = $(".control-post-add-picture").val() || null;

var dataurl = $(".post-picture img").attr("src");
values.picture = dataurl ? dataurl.split(",")[1] : ""
// validations
if(!values.parent_post && !values.title) {
frappe.msgprint(__("Please enter title!"));
return;
} else if(!values.content) {
frappe.msgprint(__("Please enter some text!"));
return;
} else if($('.post-editor [data-fieldname="event_datetime"]').length && !values.event_datetime) {
frappe.msgprint(__("Please enter Event's Date and Time!"));
return;
}
// post process
// convert links in content
values.content = website.process_external_links(values.content);
return values;
},
process_external_links: function(content) {
return content.replace(/([^\s]*)(http|https|ftp):\/\/[^\s\[\]\(\)]+/g, function(match, p1) {
// mimicing look behind! should not have anything in p1
// replace(/match/g)
// replace(/(p1)(p2)/g)
// so, when there is a character before http://, it shouldn't be replaced!
if(p1) return match;
return "["+match+"]("+match+")";
});
},
add_picture: function() {
if (this.type === 'file' && this.files && this.files.length > 0) {
$.each(this.files, function (idx, fileobj) {
if (/^image\//.test(fileobj.type)) {
$.canvasResize(fileobj, {
width: 500,
height: 0,
crop: false,
quality: 80,
callback: function(data, width, height) {
$(".post-picture").removeClass("hide").find("img").attr("src", data);
}
});
}
});
}
return false;
},
setup_tasks_editor: function() {
// assign events
var $post_editor = $(".post-editor");
var $control_assign = $post_editor.find('.control-assign');
var bind_close = function() {
var close = $post_editor.find("a.close")
if(close.length) {
close.on("click", function() {
// clear assignment
$post_editor.find(".assigned-to").addClass("hide");
$post_editor.find(".assigned-user").html("");
$post_editor.find('[data-fieldname="assigned_to"]').val(null);
$control_assign.val(null);
});
}
}
if($control_assign.length) {
website.setup_autosuggest({
$control: $control_assign,
select: function(value, item) {
var $assigned_to = $post_editor.find(".assigned-to").removeClass("hide");
$assigned_to.find(".assigned-user").html(item.user_html);
$post_editor.find('[data-fieldname="assigned_to"]').val(value);
bind_close();
},
method: "frappe.templates.website_group.post.suggest_user"
});
bind_close();
}
},
setup_event_editor: function() {
var $post_editor = $(".post-editor");
var $control_event = $post_editor.find('.control-event').empty();
var $event_field = $post_editor.find('[data-fieldname="event_datetime"]');

var set_event = function($control) {
var datetime = website.datetimepicker.obj_to_str($control_event.datepicker("getDate"));
if($event_field.val() !== datetime) {
$event_field.val(datetime);
}
};

website.setup_datepicker({
$control: $control_event,
onClose: function() { set_event($control_event) }
});

if($event_field.val()) {
$control_event.val(website.datetimepicker.format_datetime($event_field.val()));
}
},
format_event_timestamps: function() {
var get_day = function(num) {
return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"][num];
}
var get_month = function(num) {
return ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"][num-1];
}
var format = function(datetime) {
if(!datetime) return "";
var date = datetime.split(" ")[0].split("-");
var time = datetime.split(" ")[1].split(":");
var tt = "am";
if(time[0] >= 12) {
time[0] = parseInt(time[0]) - 12;
tt = "pm";
}
if(!parseInt(time[0])) {
time[0] = 12;
}
var hhmm = [time[0], time[1]].join(":")
// DD, d MM, yy hh:mm tt
var dateobj = new Date(date[0], date[1], date[2])
return repl("%(day)s, %(date)s %(month)s, %(year)s %(time)s", {
day: get_day(dateobj.getDay()),
date: date[2],
month: get_month(dateobj.getMonth()),
year: date[0],
time: hhmm + " " + tt
})
}
$(".event-timestamp").each(function() {
$(this).html(format($(this).attr("data-timestamp")));
})
},
toggle_earlier_replies: function() {
var $earlier_replies = $(".child-post").slice(0, $(".child-post").length - 2);
var $btn = $(".btn-earlier-replies").on("click", function() {
if($earlier_replies.hasClass("hide")) {
$earlier_replies.removeClass("hide");
$(".btn-earlier-label").html("Hide");
} else {
$earlier_replies.addClass("hide");
$(".btn-earlier-label").html("Show");
}
});
if($earlier_replies.length) {
$btn.toggleClass("hide", false).click();
}
},
toggle_edit: function(only_owner) {
if(only_owner) {
var user = frappe.get_cookie("user_id");
$(".edit-post").each(function() {
$(this).toggleClass("hide", !(website.access.write && $(this).attr("data-owner")===user));
});
} else {
$(".edit-post").toggleClass("hide", !website.access.write);
}
},
toggle_upvote: function() {
if(!website.access.read || !website.upvote) {
$(".upvote").remove();
}
},
toggle_post_editor: function() {
$(".post-editor").toggleClass("hide", !website.access.write);
},
setup_upvote: function() {
if(window.website.setup_upvote_done) return;
window.website.setup_upvote_done = true;
$(document).on("click", ".post-list .upvote a, .parent-post .upvote a", function() {
console.log("clicked");
var sid = frappe.get_cookie("sid");
if(!sid || sid==="Guest") {
frappe.msgprint(__("Please login to Upvote!"));
return;
}
var $post = $(this).parents(".post");
var post = $post.attr("data-name");
var $btn = $(this).prop("disabled", true);
$.ajax({
url: "/",
type: "POST",
data: {
cmd: "frappe.website.doctype.user_vote.user_vote.set_vote",
ref_doctype: "Post",
ref_name: post
},
statusCode: {
200: function(data) {
if(data.exc) {
console.log(data.exc);
} else {
var text_class = data.message === "ok" ? "text-success" : "text-danger";
if(data.message==="ok") {
var count = parseInt($post.find(".upvote-count").text());
$post.find(".upvote-count").text(count + 1).removeClass("hide");
}
$btn.addClass(text_class);
setTimeout(function() { $btn.removeClass(text_class); }, 2000);
}
}
}
}).always(function() {
$btn.prop("disabled", false);
});
return false;
});
},
setup_autosuggest: function(opts) {
if(opts.$control.hasClass("ui-autocomplete-input")) return;
frappe.require("/assets/frappe/js/lib/jquery/jquery.ui.min.js");
frappe.require("/assets/frappe/js/lib/jquery/bootstrap_theme/jquery-ui.selected.css");

var $user_suggest = opts.$control.autocomplete({
source: function(request, response) {
$.ajax({
url: "/",
data: {
cmd: opts.method,
term: request.term,
group: website.group
},
success: function(data) {
if(data.exc) {
console.log(data.exc);
} else {
response(data.message);
}
}
});
},
select: function(event, ui) {
opts.$control.val("");
opts.select(ui.item.user, ui.item);
}
});
$user_suggest.data( "ui-autocomplete" )._renderItem = function(ul, item) {
return $("<li>").html("<a style='padding: 5px;'>" + item.user_html + "</a>")
.css("padding", "5px")
.appendTo(ul);
};
return opts.$control
},
setup_datepicker: function(opts) {
if(opts.$control.hasClass("hasDatetimepicker")) return;
// libs required for datetime picker
frappe.require("/assets/frappe/js/lib/jquery/jquery.ui.min.js");
frappe.require("/assets/frappe/js/lib/jquery/bootstrap_theme/jquery-ui.selected.css");
frappe.require("/assets/frappe/js/lib/jquery/jquery.ui.slider.min.js");
frappe.require("/assets/frappe/js/lib/jquery/jquery.ui.sliderAccess.js");
frappe.require("/assets/frappe/js/lib/jquery/jquery.ui.timepicker-addon.css");
frappe.require("/assets/frappe/js/lib/jquery/jquery.ui.timepicker-addon.js");

opts.$control.datetimepicker({
timeFormat: "hh:mm tt",
dateFormat: 'DD, d MM, yy',
changeYear: true,
yearRange: "-70Y:+10Y",
stepMinute: 5,
hour: 10,
onClose: opts.onClose
});
website.setup_datetime_functions();
return opts.$control;
},
setup_datetime_functions: function() {
// requires datetime picker
frappe.provide("website.datetimepicker");
website.datetimepicker.str_to_obj = function(datetime_str) {
return $.datepicker.parseDateTime("yy-mm-dd", "HH:mm:ss", datetime_str);
};

website.datetimepicker.obj_to_str = function(datetime) {
if(!datetime) {
return "";
}
// requires datepicker
var date_str = $.datepicker.formatDate("yy-mm-dd", datetime)
var time_str = $.datepicker.formatTime("HH:mm:ss", {
hour: datetime.getHours(),
minute: datetime.getMinutes(),
second: datetime.getSeconds()
})
return date_str + " " + time_str;
};

website.datetimepicker.format_datetime = function(datetime) {
if (typeof(datetime)==="string") {
datetime = website.datetimepicker.str_to_obj(datetime);
}
var date_str = $.datepicker.formatDate("DD, d MM, yy", datetime)
var time_str = $.datepicker.formatTime("hh:mm tt", {
hour: datetime.getHours(),
minute: datetime.getMinutes(),
second: datetime.getSeconds()
})
return date_str + " " + time_str;
}
},
setup_settings: function() {
// autosuggest
website.setup_autosuggest({
$control: $(".add-user-control"),
select: function(value) {
website.add_sitemap_permission(value);
},
method: "frappe.templates.website_group.settings.suggest_user"
});

// trigger for change permission
$(".permission-editor-area").on("click", ".sitemap-permission [type='checkbox']",
website.update_permission);
$(".permission-editor-area").find(".btn-add-group").on("click", website.add_group);
$(".btn-settings").parent().addClass("active");
// disabled public_write if not public_read
var control_public_read = $(".control-add-group-public_read").click(function() {
if(!$(this).prop("checked")) {
$(".control-add-group-public_write").prop("checked", false).prop("disabled", true);
} else {
$(".control-add-group-public_write").prop("disabled", false);
}
}).trigger("click").trigger("click"); // hack
},
add_group: function() {
var $control = $(".control-add-group"),
$btn = $(".btn-add-group");

if($control.val()) {
$btn.prop("disabled", true);
$.ajax({
url:"/",
type:"POST",
data: {
cmd:"frappe.templates.website_group.settings.add_website_group",
group: website.group,
new_group: $control.val(),
group_type: $(".control-add-group-type").val(),
public_read: $(".control-add-group-public_read").is(":checked") ? 1 : 0,
public_write: $(".control-add-group-public_write").is(":checked") ? 1 : 0
},
statusCode: {
403: function() {
frappe.msgprint(__("Name not permitted"));
},
200: function(data) {
if(data.exc) {
console.log(data.exc);
if(data._server_messages) frappe.msgprint(data._server_messages);
} else {
frappe.msgprint(__("Group Added, refreshing..."));
setTimeout(function() { window.location.reload(); }, 1000)
}
}
}
}).always(function() {
$btn.prop("disabled",false);
$control.val("");
})
}
},
update_permission: function() {
var $chk = $(this);
var $tr = $chk.parents("tr:first");
$chk.prop("disabled", true);
$.ajax({
url: "/",
type: "POST",
data: {
cmd: "frappe.templates.website_group.settings.update_permission",
user: $tr.attr("data-user"),
perm: $chk.attr("data-perm"),
value: $chk.prop("checked") ? "1" : "0",
group: website.group
},
statusCode: {
403: function() {
frappe.msgprint(__("Not allowed"));
},
200: function(data) {
$chk.prop("disabled", false);
if(data.exc) {
$chk.prop("checked", !$chk.prop("checked"));
console.log(data.exc);
} else {
if(!$tr.find(":checked").length) $tr.remove();
}
}
},
});
},
add_sitemap_permission: function(user) {
$.ajax({
url: "/",
type: "POST",
data: {
cmd: "frappe.templates.website_group.settings.add_sitemap_permission",
user: user,
group: website.group
},
success: function(data) {
$(".add-user-control").val("");
if(data.exc) {
console.log(data.exc);
} else {
$(data.message).prependTo($(".permission-editor tbody"));
}
}
});
},
update_group_description: function() {
$(".btn-update-description").prop("disabled", true);
$.ajax({
url: "/",
type: "POST",
data: {
cmd: "frappe.templates.website_group.settings.update_description",
description: $(".control-description").val() || "",
group: website.group
},
success: function(data) {
window.location.reload();
}
}).always(function() { $(".btn-update-description").prop("disabled", false); });
}
});

$(document).on("apply_permissions", function() {
website.toggle_permitted();
});

+ 0
- 77
frappe/website/permissions.py 查看文件

@@ -1,77 +0,0 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt

from __future__ import unicode_literals
import frappe

def remove_empty_permissions():
permissions_cache_to_be_cleared = frappe.db.sql_list("""select distinct user
from `tabWebsite Route Permission`
where ifnull(`read`, 0)=0 and ifnull(`write`, 0)=0 and ifnull(`admin`, 0)=0""")

frappe.db.sql("""delete from `tabWebsite Route 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(doc, pathname, user=None):
user = user or frappe.session.user
key = "website_route_permissions:{}".format(user)

cache = frappe.cache()
permissions = cache.get_value(key) or {}
if not permissions.get(doc.name):
permissions[doc.name] = _get_access(doc, pathname, user)
cache.set_value(key, permissions)

return permissions.get(doc.name)

def _get_access(doc, pathname, user):
read = write = admin = private_read = 0

if user == "Guest":
return { "read": doc.public_read, "write": 0, "admin": 0 }

if doc.public_write:
read = write = 1
elif doc.public_read:
read = 1

for perm in frappe.db.sql("""select
`tabWebsite Route Permission`.`read`,
`tabWebsite Route Permission`.`write`,
`tabWebsite Route Permission`.`admin`,
`tabWebsite Group`.lft,
`tabWebsite Group`.rgt
from
`tabWebsite Route Permission`, `tabWebsite Group`
where
`tabWebsite Route Permission`.website_route = %s and
`tabWebsite Route Permission`.user = %s and
`tabWebsite Route Permission`.reference = `tabWebsite Group`.name
order by `tabWebsite Group`.lft asc""", (user, pathname), as_dict=True):
if perm.lft <= doc.lft and perm.rgt >= doc.rgt:
if not (doc.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

else:
read = write = admin = private_read = 1

return { "read": read, "write": write, "admin": admin, "private_read": private_read }

def clear_permissions(users=None):
if isinstance(users, basestring):
users = [users]
elif users is None:
users = frappe.db.sql_list("""select name from `tabUser`""")

cache = frappe.cache()
for user in users:
cache.delete_value("website_route_permissions:{}".format(user))

+ 0
- 2
frappe/website/render.py 查看文件

@@ -10,7 +10,6 @@ from werkzeug.wrappers import Response

from frappe.website.context import get_context
from frappe.website.utils import scrub_relative_urls, get_home_page, can_cache, delete_page_cache
from frappe.website.permissions import clear_permissions
from frappe.website.router import clear_sitemap

class PageNotFoundError(Exception): pass
@@ -184,7 +183,6 @@ def clear_cache(path=None):
clear_sitemap()
frappe.clear_cache("Guest")
frappe.cache().delete_value("_website_pages")
clear_permissions()

for method in frappe.get_hooks("website_clear_cache"):
frappe.get_attr(method)(path)


正在加载...
取消
保存