database.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import json
  2. import os
  3. import time
  4. import settings
  5. import sqlite3
  6. import gitosis_configen
  7. # Open (or create database)
  8. DB_PATH = os.path.abspath(settings.database_path) # necessary since cwd changes later.
  9. db = sqlite3.connect(DB_PATH)
  10. # Returns SQLite rows as dictionaries instead of tuples.
  11. # https://docs.python.org/3/library/sqlite3.html#sqlite3.Connection.row_factory
  12. db.row_factory = sqlite3.Row
  13. def debug_log(message):
  14. with open(os.path.join("..",settings.log_path), mode = "a") as file:
  15. file.write(str(time.thread_time()) + " " + message + "\n")
  16. file.close()
  17. # Create database tables if they do not exist, for example if it's a new database.
  18. with db:
  19. # List of remote actors that follow a local actor
  20. db.execute("""
  21. CREATE TABLE IF NOT EXISTS follower(
  22. forge TEXT NOT NULL,
  23. remote_actor TEXT NOT NULL,
  24. local_actor TEXT NOT NULL,
  25. PRIMARY KEY(forge, remote_actor, local_actor)
  26. )""")
  27. db.execute("CREATE INDEX IF NOT EXISTS forge_idx ON follower (forge ASC)")
  28. db.execute("CREATE INDEX IF NOT EXISTS remote_actor_idx ON follower (remote_actor ASC)")
  29. db.execute("CREATE INDEX IF NOT EXISTS local_actor_idx ON follower (local_actor ASC)")
  30. # List of local actors that follow a remote actor
  31. db.execute("""
  32. CREATE TABLE IF NOT EXISTS following(
  33. forge TEXT NOT NULL,
  34. local_actor TEXT NOT NULL,
  35. remote_actor TEXT NOT NULL,
  36. PRIMARY KEY(forge, local_actor, remote_actor)
  37. )""")
  38. db.execute("CREATE INDEX IF NOT EXISTS forge_idx ON following (forge ASC)")
  39. db.execute("CREATE INDEX IF NOT EXISTS local_actor_idx ON following (local_actor ASC)")
  40. db.execute("CREATE INDEX IF NOT EXISTS remote_actor_idx ON following (remote_actor ASC)")
  41. # INBOX table used to store incoming messages
  42. db.execute("""
  43. CREATE TABLE IF NOT EXISTS inbox(
  44. forge TEXT NOT NULL,
  45. actor TEXT NOT NULL,
  46. message TEXT NOT NULL
  47. )""")
  48. db.execute("CREATE INDEX IF NOT EXISTS forge_idx ON inbox (forge ASC)")
  49. db.execute("CREATE INDEX IF NOT EXISTS actor_idx ON inbox (actor ASC)")
  50. # OUTBOX table used to store outgoing messages
  51. db.execute("""
  52. CREATE TABLE IF NOT EXISTS outbox(
  53. forge TEXT NOT NULL,
  54. actor TEXT NOT NULL,
  55. message TEXT NOT NULL
  56. )""")
  57. db.execute("CREATE INDEX IF NOT EXISTS forge_idx ON outbox (forge ASC)")
  58. db.execute("CREATE INDEX IF NOT EXISTS actor_idx ON outbox (actor ASC)")
  59. # USERS table to store users. Associations of users with repos is handled by gitosis/gitolite config files.
  60. db.execute("""
  61. CREATE TABLE IF NOT EXISTS users(
  62. username TEXT NOT NULL,
  63. email TEXT NOT NULL,
  64. password TEXT NOT NULL,
  65. public_key TEXT NOT NULL
  66. )""")
  67. db.execute("CREATE INDEX IF NOT EXISTS username_idx ON users (username ASC)")
  68. # list of collaborations
  69. db.execute("""
  70. CREATE TABLE IF NOT EXISTS collaborations(
  71. repository TEXT NOT NULL,
  72. collaborator TEXT NOT NULL
  73. )""")
  74. db.execute("CREATE INDEX IF NOT EXISTS repository_idx ON collaborations (repository ASC)")
  75. db.execute("CREATE INDEX IF NOT EXISTS collaborator_idx ON collaborations (collaborator ASC)")
  76. # list of repositories
  77. db.execute("""
  78. CREATE TABLE IF NOT EXISTS repositories(
  79. repository TEXT NOT NULL,
  80. owner TEXT NOT NULL
  81. )""")
  82. db.execute("CREATE INDEX IF NOT EXISTS repository_idx ON repositories (repository ASC)")
  83. db.execute("CREATE INDEX IF NOT EXISTS owner_idx ON repositories (owner ASC)")
  84. # Add a remote follower to a local actor
  85. def add_follower(forge, remote_actor, local_actor):
  86. with db:
  87. db.execute (
  88. """
  89. INSERT OR IGNORE INTO follower (forge, remote_actor, local_actor)
  90. VALUES (?, ?, ?)
  91. """,
  92. [ forge, remote_actor, local_actor ]
  93. )
  94. # Add a local actor that is following a remote actor
  95. def add_following(forge, local_actor, remote_actor):
  96. with db:
  97. db.execute (
  98. """
  99. INSERT OR IGNORE INTO following (forge, local_actor, remote_actor)
  100. VALUES (?, ?, ?)
  101. """,
  102. [ forge, local_actor, remote_actor ]
  103. )
  104. # Get a local user
  105. def get_user_local(username):
  106. with db:
  107. cursor = db.execute (
  108. """
  109. SELECT username, email, password, public_key
  110. FROM users
  111. WHERE username = ?
  112. """,
  113. [ username ]
  114. )
  115. result = cursor.fetchone()
  116. if settings.DEBUG:
  117. debug_log("db: retrieving user " + str(result))
  118. return result
  119. def add_collaboration(repository, collaborator):
  120. with db:
  121. db.execute (
  122. """
  123. INSERT OR IGNORE INTO collaborations (repository, collaborator)
  124. VALUES (?, ?)
  125. """,
  126. [repository, collaborator]
  127. )
  128. def add_repository(repository, owner):
  129. with db:
  130. db.execute (
  131. """
  132. INSERT OR IGNORE INTO repositories (repository, owner)
  133. VALUES (?, ?)
  134. """,
  135. [repository, owner]
  136. )
  137. # Add a local user
  138. def add_user(username, email, password, public_key):
  139. with db:
  140. if settings.DEBUG:
  141. debug_log("db: adding user " + str([username, email, password, public_key]))
  142. db.execute (
  143. """
  144. INSERT OR IGNORE INTO users (username, email, password, public_key)
  145. VALUES (?, ?, ?, ?)
  146. """,
  147. [ username, email, password, public_key ]
  148. )
  149. if not get_user_local(username):
  150. debug_log("ERROR: USER WAS NOT CREATED " + username )
  151. return False
  152. return True
  153. # Get the list of remote actors that follow a local actor
  154. def get_followers(forge, local_actor):
  155. with db:
  156. cursor = db.execute (
  157. """
  158. SELECT remote_actor
  159. FROM follower
  160. WHERE forge = ?
  161. AND local_actor = ?
  162. """,
  163. [ forge, local_actor ]
  164. )
  165. results = cursor.fetchall()
  166. followers = [ follower['remote_actor'] for follower in results ]
  167. return followers
  168. # Store a new message in the INBOX
  169. def store_inbox(forge, actor, message):
  170. with db:
  171. db.execute (
  172. """
  173. INSERT OR IGNORE INTO inbox (forge, actor, message)
  174. VALUES (?, ?, ?)
  175. """,
  176. [ forge, actor, json.dumps(message) ]
  177. )
  178. # Store a new message in the OUTBOX
  179. def store_outbox(forge, actor, message):
  180. with db:
  181. db.execute (
  182. """
  183. INSERT OR IGNORE INTO outbox (forge, actor, message)
  184. VALUES (?, ?, ?)
  185. """,
  186. [ forge, actor, json.dumps(message) ]
  187. )
  188. # Get all INBOX messages for an actor
  189. def get_inbox_messages(forge, actor):
  190. with db:
  191. cursor = db.execute (
  192. """
  193. SELECT message
  194. FROM inbox
  195. WHERE forge = ?
  196. AND actor = ?
  197. """,
  198. [ forge, actor ]
  199. )
  200. results = cursor.fetchall()
  201. messages = [ json.loads(result['message']) for result in results ]
  202. return messages
  203. def get_collaborators(repository):
  204. with db:
  205. cursor = db.execute (
  206. """
  207. SELECT collaborator
  208. FROM collaborations
  209. WHERE repository = ?
  210. """,
  211. [ repository ]
  212. )
  213. results = cursor.fetchall()
  214. collaborators = [ result['collaborator'] for result in results ]
  215. return collaborators
  216. def get_repositories():
  217. with db:
  218. cursor = db.execute (
  219. """
  220. SELECT repository, owner
  221. FROM repositories
  222. """
  223. )
  224. results = cursor.fetchall()
  225. return results
  226. def regenerate_gitosis_config():
  227. debug_log("generating config")
  228. config = gitosis_configen.Config()
  229. for r in get_repositories():
  230. conf_r = gitosis_configen.Repository()
  231. conf_r.owner = r["owner"]
  232. conf_r.name = r["repository"]
  233. conf_r.collaborators = get_collaborators(r["repository"])
  234. debug_log("appending conf repository "+conf_r.print_())
  235. config.append(conf_r)
  236. debug_log("flushing")
  237. config.flush()
  238. debug_log("flushed")
  239. #make sure to do git push afterwards wherever you use it otherwise not effective
  240. pass