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