Esempio n. 1
0
def toggle_favourite(key):
	"""
	'Like' a dataset

	Marks the dataset as being liked by the currently active user, which can be
	used for organisation in the front-end.

	:param str key: Key of the dataset to mark as favourite.

	:return: A JSON object with the status of the request
	:return-schema: {type=object,properties={success={type=boolean},favourite_status={type=boolean}}}

	:return-error 404:  If the dataset key was not found
	"""
	try:
		dataset = DataSet(key=key, db=db)
	except TypeError:
		return error(404, error="Dataset does not exist.")

	current_status = db.fetchone("SELECT * FROM users_favourites WHERE name = %s AND key = %s",
								 (current_user.get_id(), dataset.key))
	if not current_status:
		db.insert("users_favourites", data={"name": current_user.get_id(), "key": dataset.key})
		return jsonify({"success": True, "favourite_status": True})
	else:
		db.delete("users_favourites", where={"name": current_user.get_id(), "key": dataset.key})
		return jsonify({"success": True, "favourite_status": False})
Esempio n. 2
0
def load_user_from_request(request):
    """
	Load user object via access token

	Access token may be supplied via a GET parameter or the Authorization
	HTTP header.

	:param request:  Flask request
	:return:  User object, or None if no valid access token was given
	"""
    token = request.args.get("access-token")

    if not token:
        token = request.headers.get("Authorization")

    if not token:
        return None

    user = db.fetchone(
        "SELECT name AS user FROM access_tokens WHERE token = %s AND (expires = 0 OR expires > %s)",
        (token, int(time.time())))
    if not user:
        return None
    else:
        db.execute(
            "UPDATE access_tokens SET calls = calls + 1 WHERE name = %s",
            (user["user"], ))
        user = User.get_by_name(user["user"])
        user.authenticate()
        return user
Esempio n. 3
0
def api_thread(datasource, board, thread_id):
    """
	Emulate 4chan thread.json API endpoint

	:param str datasource:  Data source ID
	:param str board:  Board name
	:param int thread_id:  Thread ID

	:request-param str format:  Data format. Can be `json` (default) or `html`.

	:return: Thread data, as a list of `posts`.

	:return-schema: {type=object,properties={posts={type=object,additionalProperties={}}}}

	:return-error 404:  If the thread ID does not exist for the given data source.
	"""
    if datasource not in config.DATASOURCES:
        return error(404, error="Invalid data source")

    thread = db.fetchone(
        "SELECT * FROM threads_" + datasource +
        " WHERE board = %s AND id = %s", (board, thread_id))

    if thread == None:
        return "Thread is not anymore available on the server."

    response = get_thread(datasource, board, thread, db)

    def strip_html(post):
        post["com"] = strip_tags(post.get("com", ""))
        return post

    response["posts"] = [strip_html(post) for post in response["posts"]]

    if not response:
        return error(404, error="No posts available for this datasource")

    elif request.args.get("format", "json") == "html":

        def format(post):
            post["com"] = format_post(post.get("com",
                                               "")).replace("\n", "<br>")
            return post

        response["posts"] = [format(post) for post in response["posts"]]
        metadata = {
            "subject":
            "".join([post.get("sub", "") for post in response["posts"]]),
            "id": response["posts"][0]["no"]
        }
        return render_template("thread.html",
                               datasource=datasource,
                               board=board,
                               posts=response["posts"],
                               thread=thread,
                               metadata=metadata)
    else:
        return jsonify(response)
Esempio n. 4
0
File: views.py Progetto: pgr-me/4cat
def show_result(key):
    """
	Show result page

	The page contains dataset details and a download link, but also shows a list
	of finished and available processors.

	:param key:  Result key
	:return:  Rendered template
	"""
    try:
        dataset = DataSet(key=key, db=db)
    except TypeError:
        abort(404)

    # child datasets are not available via a separate page - redirect to parent
    if dataset.key_parent:
        genealogy = dataset.get_genealogy()
        nav = ",".join([family.key for family in genealogy])
        url = "/results/%s/#nav=%s" % (genealogy[0].key, nav)
        return redirect(url)

    # load list of processors compatible with this dataset
    is_processor_running = False

    # show preview
    if dataset.is_finished() and dataset.num_rows > 0:
        preview = get_preview(dataset)
    else:
        preview = None

    is_favourite = (db.fetchone(
        "SELECT COUNT(*) AS num FROM users_favourites WHERE name = %s AND key = %s",
        (current_user.get_id(), dataset.key))["num"] > 0)

    # if the datasource is configured for it, this dataset may be deleted at some point
    datasource = dataset.parameters.get("datasource", "")
    if datasource in backend.all_modules.datasources and backend.all_modules.datasources[
            datasource].get("expire-datasets", None):
        timestamp_expires = dataset.timestamp + int(
            backend.all_modules.datasources[datasource].get("expire-datasets"))
    else:
        timestamp_expires = None

    # we can either show this view as a separate page or as a bunch of html
    # to be retrieved via XHR
    standalone = "processors" not in request.url
    template = "result.html" if standalone else "result-details.html"
    return render_template(template,
                           preview=preview,
                           dataset=dataset,
                           parent_key=dataset.key,
                           processors=backend.all_modules.processors,
                           is_processor_running=is_processor_running,
                           messages=get_flashed_messages(),
                           is_favourite=is_favourite,
                           timestamp_expires=timestamp_expires)
Esempio n. 5
0
def show_results(page):
	"""
	Show results overview

	For each result, available analyses are also displayed.

	:return:  Rendered template
	"""
	page_size = 20
	offset = (page - 1) * page_size

	where = ["key_parent = ''"]
	replacements = []

	query_filter = request.args.get("filter", "")

	depth = request.args.get("depth", "own")
	if depth not in ("own", "favourites", "all"):
		depth = "own"

	if depth == "own":
		where.append("parameters::json->>'user' = %s")
		replacements.append(current_user.get_id())

	if depth == "favourites":
		where.append("key IN ( SELECT key FROM users_favourites WHERE name = %s )")
		replacements.append(current_user.get_id())

	if query_filter:
		where.append("query LIKE %s")
		replacements.append("%" + query_filter + "%")

	where = " AND ".join(where)

	num_datasets = db.fetchone("SELECT COUNT(*) AS num FROM datasets WHERE " + where, tuple(replacements))["num"]
	
	replacements.append(page_size)
	replacements.append(offset)
	datasets = db.fetchall("SELECT key FROM datasets WHERE " + where + " ORDER BY timestamp DESC LIMIT %s OFFSET %s",
						   tuple(replacements))
	
	if not datasets and page != 1:
		abort(404)

	pagination = Pagination(page, page_size, num_datasets)
	filtered = []
	processors = backend.all_modules.processors

	for dataset in datasets:
		filtered.append(DataSet(key=dataset["key"], db=db))

	favourites = [row["key"] for row in
				  db.fetchall("SELECT key FROM users_favourites WHERE name = %s", (current_user.get_id(),))]

	return render_template("results.html", filter={"filter": query_filter}, depth=depth, datasets=filtered,
						   pagination=pagination, favourites=favourites)
Esempio n. 6
0
	def get_by_name(name):
		"""
		Get user object for given user name

		:return:  User object, or `None` for invalid user name
		"""
		user = db.fetchone("SELECT * FROM users WHERE name = %s", (name,))
		if not user:
			return None
		else:
			return User(user)
Esempio n. 7
0
	def get_by_token(token):
		"""
		Get user object for given token, if token is valid

		:return:  User object, or `None` for invalid token
		"""
		user = db.fetchone(
			"SELECT * FROM users WHERE register_token = %s AND (timestamp_token = 0 OR timestamp_token > %s)",
			(token, int(time.time()) - (3 * 86400)))
		if not user:
			return None
		else:
			return User(user)
Esempio n. 8
0
def request_token():
    """
	Request an access token

	Requires that the user is currently logged in to 4CAT.

	:return: An object with one item `token`

	:return-schema={type=object,properties={token={type=string}}}

	:return-error 403:  If the user is logged in with an anonymous account.
	"""
    if current_user.get_id() == "autologin":
        # access tokens are only for 'real' users so we can keep track of who
        # (ab)uses them
        return error(403,
                     error="Anonymous users may not request access tokens.")

    token = db.fetchone(
        "SELECT * FROM access_tokens WHERE name = %s AND (expires = 0 OR expires > %s)",
        (current_user.get_id(), int(time.time())))

    if token:
        token = token["token"]
    else:
        token = current_user.get_id() + str(time.time())
        token = hashlib.sha256(token.encode("utf8")).hexdigest()
        token = {
            "name": current_user.get_id(),
            "token": token,
            "expires": int(time.time()) + (365 * 86400)
        }

        # delete any expired tokens
        db.delete("access_tokens", where={"name": current_user.get_id()})

        # save new token
        db.insert("access_tokens", token)

    if request.args.get("forward"):
        # show HTML page
        return redirect(url_for("show_access_tokens"))
    else:
        # show JSON response (by default)
        return jsonify(token)
Esempio n. 9
0
	def get_by_login(name, password):
		"""
		Get user object, if login is correct

		If the login data supplied to this method is correct, a new user object
		that is marked as authenticated is returned.

		:param name:  User name
		:param password:  User password
		:return:  User object, or `None` if login was invalid
		"""
		user = db.fetchone("SELECT * FROM users WHERE name = %s", (name,))
		if not user or not user.get("password", None):
			# registration not finished yet
			return None
		elif not user or not bcrypt.checkpw(password.encode("ascii"), user["password"].encode("ascii")):
			# non-existing user or wrong password
			return None
		else:
			# valid login!
			return User(user, authenticated=True)
Esempio n. 10
0
def check_dataset():
	"""
	Check dataset status

	Requires authentication by logging in or providing a valid access token.

	:request-param str key:  ID of the dataset for which to return the status
	:return: Dataset status, containing the `status`, `query`, number of `rows`,
	         the dataset `key`, whether the dataset is `done`, the `path` of the
	         result file and whether the dataset is `empty`.

	:return-schema: {
		type=object,
		properties={
			status={type=string},
			query={type=string},
			rows={type=integer},
			key={type=string},
			done={type=boolean},
			path={type=string},
			empty={type=boolean},
			is_favourite={type=boolean}
		}
	}

	:return-error 404:  If the dataset does not exist.
	"""
	dataset_key = request.args.get("key")
	try:
		dataset = DataSet(key=dataset_key, db=db)
	except TypeError:
		return error(404, error="Dataset does not exist.")

	results = dataset.check_dataset_finished()
	if results == 'empty':
		dataset_data = dataset.data
		dataset_data["parameters"] = json.loads(dataset_data["parameters"])
		path = False
	elif results:
		# Return absolute folder when using localhost for debugging
		path = results.name
		dataset_data = dataset.data
		dataset_data["parameters"] = json.loads(dataset_data["parameters"])
	else:
		path = ""

	status = {
		"status": dataset.get_status(),
		"status_html": render_template("result-status.html", dataset=dataset),
		"label": dataset.get_label(),
		"query": dataset.data["query"],
		"rows": dataset.data["num_rows"],
		"key": dataset_key,
		"done": True if dataset.is_finished() else False,
		"path": path,
		"empty": (dataset.data["num_rows"] == 0),
		"is_favourite": (db.fetchone("SELECT COUNT(*) AS num FROM users_favourites WHERE name = %s AND key = %s",
									 (current_user.get_id(), dataset.key))["num"] > 0)
	}

	return jsonify(status)