ContentFilterStorage.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import os
  2. import json
  3. import logging
  4. import collections
  5. import time
  6. from Debug import Debug
  7. from Plugin import PluginManager
  8. from Config import config
  9. from util import helper
  10. class ContentFilterStorage(object):
  11. def __init__(self, site_manager):
  12. self.log = logging.getLogger("ContentFilterStorage")
  13. self.file_path = "%s/filters.json" % config.data_dir
  14. self.site_manager = site_manager
  15. self.file_content = self.load()
  16. # Set default values for filters.json
  17. if not self.file_content:
  18. self.file_content = {}
  19. # Site blacklist renamed to site blocks
  20. if "site_blacklist" in self.file_content:
  21. self.file_content["siteblocks"] = self.file_content["site_blacklist"]
  22. del self.file_content["site_blacklist"]
  23. for key in ["mutes", "siteblocks", "includes"]:
  24. if key not in self.file_content:
  25. self.file_content[key] = {}
  26. self.include_filters = collections.defaultdict(set) # Merged list of mutes and blacklists from all include
  27. self.includeUpdateAll(update_site_dbs=False)
  28. def load(self):
  29. # Rename previously used mutes.json -> filters.json
  30. if os.path.isfile("%s/mutes.json" % config.data_dir):
  31. self.log.info("Renaming mutes.json to filters.json...")
  32. os.rename("%s/mutes.json" % config.data_dir, self.file_path)
  33. if os.path.isfile(self.file_path):
  34. try:
  35. return json.load(open(self.file_path))
  36. except Exception as err:
  37. self.log.error("Error loading filters.json: %s" % err)
  38. return None
  39. else:
  40. return None
  41. def includeUpdateAll(self, update_site_dbs=True):
  42. s = time.time()
  43. new_include_filters = collections.defaultdict(set)
  44. # Load all include files data into a merged set
  45. for include_path in self.file_content["includes"]:
  46. address, inner_path = include_path.split("/", 1)
  47. try:
  48. content = self.site_manager.get(address).storage.loadJson(inner_path)
  49. except Exception as err:
  50. self.log.warning(
  51. "Error loading include %s: %s" %
  52. (include_path, Debug.formatException(err))
  53. )
  54. continue
  55. for key, val in content.iteritems():
  56. if type(val) is not dict:
  57. continue
  58. new_include_filters[key].update(val.keys())
  59. mutes_added = new_include_filters["mutes"].difference(self.include_filters["mutes"])
  60. mutes_removed = self.include_filters["mutes"].difference(new_include_filters["mutes"])
  61. self.include_filters = new_include_filters
  62. if update_site_dbs:
  63. for auth_address in mutes_added:
  64. self.changeDbs(auth_address, "remove")
  65. for auth_address in mutes_removed:
  66. if not self.isMuted(auth_address):
  67. self.changeDbs(auth_address, "load")
  68. num_mutes = len(self.include_filters["mutes"])
  69. num_siteblocks = len(self.include_filters["siteblocks"])
  70. self.log.debug(
  71. "Loaded %s mutes, %s blocked sites from %s includes in %.3fs" %
  72. (num_mutes, num_siteblocks, len(self.file_content["includes"]), time.time() - s)
  73. )
  74. def includeAdd(self, address, inner_path, description=None):
  75. self.file_content["includes"]["%s/%s" % (address, inner_path)] = {
  76. "date_added": time.time(),
  77. "address": address,
  78. "description": description,
  79. "inner_path": inner_path
  80. }
  81. self.includeUpdateAll()
  82. self.save()
  83. def includeRemove(self, address, inner_path):
  84. del self.file_content["includes"]["%s/%s" % (address, inner_path)]
  85. self.includeUpdateAll()
  86. self.save()
  87. def save(self):
  88. s = time.time()
  89. helper.atomicWrite(self.file_path, json.dumps(self.file_content, indent=2, sort_keys=True))
  90. self.log.debug("Saved in %.3fs" % (time.time() - s))
  91. def isMuted(self, auth_address):
  92. if auth_address in self.file_content["mutes"] or auth_address in self.include_filters["mutes"]:
  93. return True
  94. else:
  95. return False
  96. def isSiteblocked(self, address):
  97. if address in self.file_content["siteblocks"] or address in self.include_filters["siteblocks"]:
  98. return True
  99. else:
  100. return False
  101. # Search and remove or readd files of an user
  102. def changeDbs(self, auth_address, action):
  103. self.log.debug("Mute action %s on user %s" % (action, auth_address))
  104. res = self.site_manager.list().values()[0].content_manager.contents.db.execute(
  105. "SELECT * FROM content LEFT JOIN site USING (site_id) WHERE inner_path LIKE :inner_path",
  106. {"inner_path": "%%/%s/%%" % auth_address}
  107. )
  108. for row in res:
  109. site = self.site_manager.sites.get(row["address"])
  110. if not site:
  111. continue
  112. dir_inner_path = helper.getDirname(row["inner_path"])
  113. for file_name in site.storage.walk(dir_inner_path):
  114. if action == "remove":
  115. site.storage.onUpdated(dir_inner_path + file_name, False)
  116. else:
  117. site.storage.onUpdated(dir_inner_path + file_name)
  118. site.onFileDone(dir_inner_path + file_name)