]> git.ipfire.org Git - ipfire.org.git/blob - src/backend/base.py
wiki: Only match usernames when a word starts with @
[ipfire.org.git] / src / backend / base.py
1 #!/usr/bin/python
2
3 import configparser
4 import io
5 import location
6 import logging
7 import ssl
8 import tempfile
9 import tornado.httpclient
10
11 from . import accounts
12 from . import asterisk
13 from . import analytics
14 from . import blog
15 from . import bugzilla
16 from . import cache
17 from . import campaigns
18 from . import database
19 from . import fireinfo
20 from . import httpclient
21 from . import iuse
22 from . import lists
23 from . import messages
24 from . import mirrors
25 from . import netboot
26 from . import nopaste
27 from . import ratelimit
28 from . import releases
29 from . import resolver
30 from . import settings
31 from . import toots
32 from . import util
33 from . import wiki
34 from . import zeiterfassung
35 from .decorators import *
36
37 DEFAULT_CONFIG = io.StringIO("""
38 [global]
39 debug = false
40 environment = testing
41
42 data_dir =
43 static_dir = %(data_dir)s/static
44 templates_dir = %(data_dir)s/templates
45 """)
46
47 # Setup logging
48 log = logging.getLogger(__name__)
49
50 class Backend(object):
51 version = 0
52
53 def __init__(self, configfile, debug=False):
54 # Read configuration file.
55 self.config = self.read_config(configfile)
56
57 # Enable debug logging if configured
58 self.debug = debug or self.config.getboolean("global", "debug")
59
60 # Setup database.
61 self.setup_database()
62
63 # Create HTTPClient
64 self.http_client = httpclient.HTTPClient(self)
65
66 # Initialize the cache
67 self.cache = cache.Cache(self)
68
69 # Initialize settings first
70 self.settings = settings.Settings(self)
71
72 # Initialize backend modules.
73 self.accounts = accounts.Accounts(self)
74 self.analytics = analytics.Analytics(self)
75 self.bugzilla = bugzilla.Bugzilla(self)
76 self.fireinfo = fireinfo.Fireinfo(self)
77 self.iuse = iuse.IUse(self)
78 self.mirrors = mirrors.Mirrors(self)
79 self.netboot = netboot.NetBoot(self)
80 self.nopaste = nopaste.Nopaste(self)
81 self.releases = releases.Releases(self)
82
83 self.blog = blog.Blog(self)
84 self.wiki = wiki.Wiki(self)
85 self.zeiterfassung = zeiterfassung.ZeiterfassungClient(self)
86
87 def read_config(self, configfile):
88 cp = configparser.ConfigParser()
89
90 # Initialize configuration with some sensible defaults
91 cp.readfp(DEFAULT_CONFIG)
92
93 # Parse file
94 cp.read(configfile)
95
96 return cp
97
98 @property
99 def environment(self):
100 """
101 Returns whether this is running in "production" or "testing"
102 """
103 return self.config.get("global", "environment")
104
105 def setup_database(self):
106 """
107 Sets up the database connection.
108 """
109 credentials = {
110 "host" : self.config.get("database", "server"),
111 "database" : self.config.get("database", "database"),
112 "user" : self.config.get("database", "username"),
113 "password" : self.config.get("database", "password"),
114 }
115
116 self.db = database.Connection(self, **credentials)
117
118 @lazy_property
119 def ssl_context(self):
120 # Create SSL context
121 context = ssl.create_default_context()
122
123 # Fetch client certificate
124 certificate = self.settings.get("client-certificate", None)
125 key = self.settings.get("client-key", None)
126
127 # Apply client certificate
128 if certificate and key:
129 with tempfile.NamedTemporaryFile(mode="w") as f_cert:
130 f_cert.write(certificate)
131 f_cert.flush()
132
133 with tempfile.NamedTemporaryFile(mode="w") as f_key:
134 f_key.write(key)
135 f_key.flush()
136
137 context.load_cert_chain(f_cert.name, f_key.name)
138
139 return context
140
141 async def load_certificate(self, certfile, keyfile):
142 with self.db.transaction():
143 # Load certificate
144 with open(certfile) as f:
145 self.settings.set("client-certificate", f.read())
146
147 # Load key file
148 with open(keyfile) as f:
149 self.settings.set("client-key", f.read())
150
151 async def run_task(self, task, *args, **kwargs):
152 tasks = {
153 "accounts:delete" : self.accounts._delete,
154 "announce-blog-posts" : self.blog.announce,
155 "check-mirrors" : self.mirrors.check_all,
156 "cleanup" : self.cleanup,
157 "get-all-emails" : self.accounts.get_all_emails,
158 "launch-campaigns" : self.campaigns.launch_manually,
159 "load-certificate" : self.load_certificate,
160 "run-campaigns" : self.campaigns.run,
161 "scan-files" : self.releases.scan_files,
162 "send-message" : self.messages.send_cli,
163 "send-all-messages" : self.messages.queue.send_all,
164 "test-ldap" : self.accounts.test_ldap,
165 "toot" : self.toots.toot,
166 "update-blog-feeds" : self.blog.update_feeds,
167 }
168
169 # Get the task from the list of all tasks
170 func = tasks.get(task, None)
171 if not func:
172 raise ValueError("Unknown task: %s" % task)
173
174 # Check if we are running in production
175 if not self.environment == "production":
176 log.warning("Refusing to run task '%s' in '%s' environment" % (task, self.environment))
177 return
178
179 # Run the task
180 r = await func(*args, **kwargs)
181
182 # If any error code has been returned,
183 # we will end the program
184 if r:
185 raise SystemExit(r)
186
187 @lazy_property
188 def asterisk(self):
189 return asterisk.Asterisk(self)
190
191 @lazy_property
192 def campaigns(self):
193 return campaigns.Campaigns(self)
194
195 @lazy_property
196 def groups(self):
197 return accounts.Groups(self)
198
199 @lazy_property
200 def lists(self):
201 return lists.Lists(self)
202
203 @lazy_property
204 def messages(self):
205 return messages.Messages(self)
206
207 @lazy_property
208 def location(self):
209 return location.Database("/var/lib/location/database.db")
210
211 def get_country_name(self, country_code):
212 try:
213 country = self.location.get_country(country_code)
214
215 # In case the country code was invalid, we return it again
216 except ValueError:
217 return country_code
218
219 if country:
220 return country.name
221
222 return country_code
223
224 @lazy_property
225 def ratelimiter(self):
226 return ratelimit.RateLimiter(self)
227
228 @lazy_property
229 def resolver(self):
230 return resolver.Resolver(tries=2, timeout=2, domains=[])
231
232 @lazy_property
233 def toots(self):
234 return toots.Toots(self)
235
236 async def cleanup(self):
237 # Cleanup message queue
238 with self.db.transaction():
239 self.messages.queue.cleanup()
240
241 # Cleanup in accounts
242 with self.db.transaction():
243 self.accounts.cleanup()
244
245 # Cleanup nopasts
246 with self.db.transaction():
247 self.nopaste.cleanup()