aboutsummaryrefslogtreecommitdiff
path: root/app/tasks/forumtasks.py
blob: 7ef437ced7ff1fdafbb1f6f321b945315fb55015 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# ContentDB
# Copyright (C) 2018  rubenwardy
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.


import flask, json, re
from flask_sqlalchemy import SQLAlchemy
from app import app
from app.models import *
from app.tasks import celery
from .phpbbparser import getProfile, getTopicsFromForum
import urllib.request
from urllib.parse import urlparse, quote_plus

@celery.task()
def checkForumAccount(username, forceNoSave=False):
	print("Checking " + username)
	try:
		profile = getProfile("https://forum.minetest.net", username)
	except OSError:
		return

	user = User.query.filter_by(forums_username=username).first()

	# Create user
	needsSaving = False
	if user is None:
		user = User(username)
		user.forums_username = username
		db.session.add(user)

	# Get github username
	github_username = profile.get("github")
	if github_username is not None and github_username.strip() != "":
		print("Updated github username for " + user.display_name + " to " + github_username)
		user.github_username = github_username
		needsSaving = True

	pic = profile.avatar
	if pic and "http" in pic:
		pic = None

	needsSaving = needsSaving or pic != user.profile_pic
	if pic:
		user.profile_pic = "https://forum.minetest.net/" + pic
	else:
		user.profile_pic = None

	# Save
	if needsSaving and not forceNoSave:
		db.session.commit()

	return needsSaving

@celery.task()
def checkAllForumAccounts(forceNoSave=False):
	needsSaving = False
	query = User.query.filter(User.forums_username.isnot(None))
	for user in query.all():
		needsSaving = checkForumAccount(user.username) or needsSaving

	if needsSaving and not forceNoSave:
		db.session.commit()

	return needsSaving


regex_tag    = re.compile(r"\[([a-z0-9_]+)\]")
BANNED_NAMES = ["mod", "game", "old", "outdated", "wip", "api", "beta", "alpha", "git"]
def getNameFromTaglist(taglist):
	for tag in reversed(regex_tag.findall(taglist)):
		if len(tag) < 30 and not tag in BANNED_NAMES and \
				not re.match(r"^[a-z]?[0-9]+$", tag):
			return tag

	return None

regex_title = re.compile(r"^((?:\[[^\]]+\] *)*)([^\[]+) *((?:\[[^\]]+\] *)*)[^\[]*$")
def parseTitle(title):
	m = regex_title.match(title)
	if m is None:
		print("Invalid title format: " + title)
		return title, getNameFromTaglist(title)
	else:
		return m.group(2).strip(), getNameFromTaglist(m.group(3))

def getLinksFromModSearch():
	links = {}

	try:
		contents = urllib.request.urlopen("https://krock-works.uk.to/minetest/modList.php").read().decode("utf-8")
		for x in json.loads(contents):
			try:
				link = x.get("link")
				if link is not None:
					links[int(x["topicId"])] = link
			except ValueError:
				pass

	except urllib.error.URLError:
		print("Unable to open krocks mod search!")
		return links

	return links

@celery.task()
def importTopicList():
	links_by_id = getLinksFromModSearch()

	info_by_id = {}
	getTopicsFromForum(11, out=info_by_id, extra={ 'type': PackageType.MOD,  'wip': False })
	getTopicsFromForum(9,  out=info_by_id, extra={ 'type': PackageType.MOD,  'wip': True  })
	getTopicsFromForum(15, out=info_by_id, extra={ 'type': PackageType.GAME, 'wip': False })
	getTopicsFromForum(50, out=info_by_id, extra={ 'type': PackageType.GAME, 'wip': True  })

	# Caches
	username_to_user = {}
	topics_by_id     = {}
	for topic in ForumTopic.query.all():
		topics_by_id[topic.topic_id] = topic

	# Create or update
	for info in info_by_id.values():
		id = int(info["id"])

		# Get author
		username = info["author"]
		user = username_to_user.get(username)
		if user is None:
			user = User.query.filter_by(forums_username=username).first()
			if user is None:
				print(username + " not found!")
				user = User(username)
				user.forums_username = username
				db.session.add(user)
			username_to_user[username] = user

		# Get / add row
		topic = topics_by_id.get(id)
		if topic is None:
			topic = ForumTopic()
			db.session.add(topic)

		# Parse title
		title, name = parseTitle(info["title"])

		# Get link
		link = links_by_id.get(id)

		# Fill row
		topic.topic_id   = int(id)
		topic.author     = user
		topic.type       = info["type"]
		topic.title      = title
		topic.name       = name
		topic.link       = link
		topic.wip        = info["wip"]
		topic.posts      = int(info["posts"])
		topic.views      = int(info["views"])
		topic.created_at = info["date"]

	db.session.commit()