]> git.lizzy.rs Git - cheatdb.git/blob - app/tasks/importtasks.py
Fix crash on mod name not specified
[cheatdb.git] / app / tasks / importtasks.py
1 import flask, json
2 from flask.ext.sqlalchemy import SQLAlchemy
3 import urllib.request
4 from urllib.parse import urlparse, quote_plus
5 from app import app
6 from app.models import *
7 from app.tasks import celery, TaskError
8
9 class GithubURLMaker:
10         def __init__(self, url):
11                 # Rewrite path
12                 import re
13                 m = re.search("^\/([^\/]+)\/([^\/]+)\/?$", url.path)
14                 if m is None:
15                         return
16
17                 user = m.group(1)
18                 repo = m.group(2)
19                 self.baseUrl = "https://raw.githubusercontent.com/{}/{}/master" \
20                                 .format(user, repo.replace(".git", ""))
21                 self.user = user
22                 self.repo = repo
23
24         def isValid(self):
25                 return self.baseUrl is not None
26
27         def getRepoURL(self):
28                 return "https://github.com/{}/{}".format(self.user, self.repo)
29
30         def getIssueTrackerURL(self):
31                 return "https://github.com/{}/{}/issues/".format(self.user, self.repo)
32
33         def getModConfURL(self):
34                 return self.baseUrl + "/mod.conf"
35
36         def getDescURL(self):
37                 return self.baseUrl + "/description.txt"
38
39         def getScreenshotURL(self):
40                 return self.baseUrl + "/placeholder.png"
41
42         def getCommitsURL(self, branch):
43                 return "https://api.github.com/repos/{}/{}/commits?sha={}" \
44                                 .format(self.user, self.repo, urllib.parse.quote_plus(branch))
45
46         def getCommitDownload(self, commit):
47                 return "https://github.com/{}/{}/archive/{}.zip" \
48                                 .format(self.user, self.repo, commit)
49
50
51 krock_list_cache = None
52 krock_list_cache_by_name = None
53 def getKrockList():
54         global krock_list_cache
55         global krock_list_cache_by_name
56
57         if krock_list_cache is None:
58                 contents = urllib.request.urlopen("http://krock-works.16mb.com/MTstuff/modList.php").read().decode("utf-8")
59                 list = json.loads(contents)
60
61                 def h(x):
62                         if not ("title"   in x and "author" in x and \
63                                         "topicId" in x and "link"   in x and x["link"] != ""):
64                                 return False
65
66                         import re
67                         m = re.search("\[([A-Za-z0-9_]+)\]", x["title"])
68                         if m is None:
69                                 return False
70
71                         x["name"] = m.group(1)
72                         return True
73
74                 def g(x):
75                         return {
76                                 "title":   x["title"],
77                                 "author":  x["author"],
78                                 "name":    x["name"],
79                                 "topicId": x["topicId"],
80                                 "link":    x["link"],
81                         }
82
83                 krock_list_cache = [g(x) for x in list if h(x)]
84                 krock_list_cache_by_name = {}
85                 for x in krock_list_cache:
86                         if not x["name"] in krock_list_cache_by_name:
87                                 krock_list_cache_by_name[x["name"]] = []
88
89                         krock_list_cache_by_name[x["name"]].append(x)
90
91         return krock_list_cache, krock_list_cache_by_name
92
93 def findModInfo(author, name, link):
94         list, lookup = getKrockList()
95
96         if name is not None and name in lookup:
97                 if len(lookup[name]) == 1:
98                         return lookup[name][0]
99
100                 for x in lookup[name]:
101                         if x["author"] == author:
102                                 return x
103
104         if link is not None and len(link) > 15:
105                 for x in list:
106                         if link in x["link"]:
107                                 return x
108
109         return None
110
111
112 def parseConf(string):
113         retval = {}
114         for line in string.split("\n"):
115                 idx = line.find("=")
116                 if idx > 0:
117                         key   = line[:idx-1].strip()
118                         value = line[idx+1:].strip()
119                         retval[key] = value
120
121         return retval
122
123
124 @celery.task()
125 def getMeta(urlstr, author):
126         url = urlparse(urlstr)
127
128         urlmaker = None
129         if url.netloc == "github.com":
130                 urlmaker = GithubURLMaker(url)
131         else:
132                 raise TaskError("Unsupported repo")
133
134         if not urlmaker.isValid():
135                 raise TaskError("Error! Url maker not valid")
136
137         result = {}
138
139         result["repo"] = urlmaker.getRepoURL()
140         result["issueTracker"] = urlmaker.getIssueTrackerURL()
141
142         try:
143                 contents = urllib.request.urlopen(urlmaker.getModConfURL()).read().decode("utf-8")
144                 conf = parseConf(contents)
145                 for key in ["name", "description", "title"]:
146                         try:
147                                 result[key] = conf[key]
148                         except KeyError:
149                                 pass
150         except OSError:
151                 print("mod.conf does not exist")
152
153         if "name" in result:
154                 result["title"] = result["name"].replace("_", " ").title()
155
156         if not "description" in result:
157                 try:
158                         contents = urllib.request.urlopen(urlmaker.getDescURL()).read().decode("utf-8")
159                         result["description"] = contents.strip()
160                 except OSError:
161                         print("description.txt does not exist!")
162
163         if "description" in result:
164                 desc = result["description"]
165                 idx = desc.find(".") + 1
166                 cutIdx = min(len(desc), 200 if idx < 5 else idx)
167                 result["short_description"] = desc[:cutIdx]
168
169         info = findModInfo(author, result.get("name"), result["repo"])
170         if info is not None:
171                 result["forumId"] = info.get("topicId")
172
173         return result
174
175 @celery.task()
176 def makeVCSRelease(id, branch):
177         release = PackageRelease.query.get(id)
178
179         if release is None:
180                 raise TaskError("No such release!")
181
182         if release.package is None:
183                 raise TaskError("No package attached to release")
184
185         url = urlparse(release.package.repo)
186
187         urlmaker = None
188         if url.netloc == "github.com":
189                 urlmaker = GithubURLMaker(url)
190         else:
191                 raise TaskError("Unsupported repo")
192
193         if not urlmaker.isValid():
194                 raise TaskError("Invalid github repo URL")
195
196         contents = urllib.request.urlopen(urlmaker.getCommitsURL(branch)).read().decode("utf-8")
197         commits = json.loads(contents)
198
199         if len(commits) == 0:
200                 raise TaskError("No commits found")
201
202         release.url = urlmaker.getCommitDownload(commits[0]["sha"])
203         release.task_id = None
204         db.session.commit()
205
206         return release.url