예제 #1
0
파일: __init__.py 프로젝트: zxhycxq/archivy
def setup(author, location):
    """Save metadata values."""
    with app.app_context():
        # save data in db
        get_db().insert({
            "type": "metadata",
            "author": author,
            "location": location
        })
    click.echo("Metadata saved!")
예제 #2
0
파일: test_cli.py 프로젝트: zxhycxq/archivy
def test_create_admin(test_app, cli_runner, click_cli):
    db = get_db()
    nb_users = len(db.search(Query().type == "user"))
    cli_runner.invoke(click_cli, ["create-admin", "__username__"],
                      input="password\npassword")

    # need to reconnect to db because it has been modified by different processes
    # so the connection needs to be updated for new changes
    db = get_db(force_reconnect=True)
    assert nb_users + 1 == len(db.search(Query().type == "user"))
    assert len(
        db.search(Query().type == "user"
                  and Query().username == "__username__"))
예제 #3
0
파일: conftest.py 프로젝트: tynen/archivy
def pocket_fixture(test_app, mocked_responses):
    """Sets up pocket key and mocked responses for testing pocket sync

    When using this fixture, all calls to https://getpocket.com/v3/get will
    succeed and return a single article whose url is https://example.com.
    """
    with test_app.app_context():
        db = get_db()

    mocked_responses.add(
        responses.POST,
        "https://getpocket.com/v3/oauth/authorize",
        json={
            "access_token": "5678defg-5678-defg-5678-defg56",
            "username": "******"
        })

    # fake /get response from pocket API
    mocked_responses.add(responses.POST, "https://getpocket.com/v3/get", json={
        'status': 1, 'complete': 1, 'list': {
            '3088163616': {
                'given_url': 'https://example.com', 'status': '0',
                'resolved_url': 'https://example.com',
                'excerpt': 'Lorem ipsum', 'is_article': '1',
            },
        },
    })

    pocket_key = {
        "type": "pocket_key",
        "consumer_key": "1234-abcd1234abcd1234abcd1234",
        "code": "dcba4321-dcba-4321-dcba-4321dc",
    }
    db.insert(pocket_key)
    return pocket_key
예제 #4
0
파일: test_cli.py 프로젝트: zxhycxq/archivy
def test_create_admin_small_password_fails(test_app, cli_runner, click_cli):
    cli_runner.invoke(click_cli, ["create-admin", "__username__"],
                      input="short\nshort")
    db = get_db()
    assert not len(
        db.search(Query().type == "user"
                  and Query().username == "__username__"))
예제 #5
0
def auth(api_key):
    with app.app_context():
        db = get_db()
        pocket = Query()
        request_data = {
            "consumer_key": api_key,
            "redirect_uri": "https://getpocket.com",
        }
        resp = requests.post(
            "https://getpocket.com/v3/oauth/request",
            json=request_data,
            headers={
                "X-Accept": "application/json",
                "Content-Type": "application/json",
            },
        )
        new_data = {
            "type": "pocket_key",
            "consumer_key": api_key,
            "code": resp.json()["code"],
        }
        if db.search(pocket.type == "pocket_key"):
            db.update(new_data, pocket.type == "pocket_key")
        else:
            db.insert(new_data)
        click.echo(
            f"Allow archivy_pocket to retrieve data to your pocket account "
            f"by visiting https://getpocket.com/auth/authorize?request_token={resp.json()['code']}"
            f"&redirect_uri=https://getpocket.com")
예제 #6
0
def test_dataobj_edit_hook(test_app, hooks_cli_runner, note_fixture, client):
    client.put(f"/api/dataobjs/{note_fixture.id}",
               json={"content": "Updated note content"})

    edit_message = get_db().search(Query().type == "edit_message")[0]
    assert f"Changes made to content of {note_fixture.title}." == edit_message[
        "content"]
예제 #7
0
def test_app():
    """Instantiate the app for each test with its own temporary data directory

    Each test using this fixture will use its own db.json and its own data
    directory, and then delete them.
    """
    # create a temporary file to isolate the database for each test
    global _app
    if _app is None:
        _app = create_click_web_app(cli, cli.cli, app)
    app_dir = tempfile.mkdtemp()
    _app.config["INTERNAL_DIR"] = app_dir
    _app.config["USER_DIR"] = app_dir
    data_dir = os.path.join(app_dir, "data")
    os.mkdir(data_dir)

    _app.config["TESTING"] = True
    _app.config["WTF_CSRF_ENABLED"] = False
    # This setups a TinyDB instance, using the `app_dir` temporary
    # directory defined above
    # Required so that `flask.current_app` can be called in data.py and
    # models.py
    # See https://flask.palletsprojects.com/en/1.1.x/appcontext/ for more
    # information.
    with _app.app_context():
        _ = get_db()
        user = {"username": "******", "password": "******"}

        User(**user).insert()
        yield _app

    # close and remove the temporary database
    shutil.rmtree(app_dir)
예제 #8
0
def complete():
    with app.app_context():
        db = get_db()
        try:
            pocket = db.search(Query().type == "pocket_key")[0]
        except:
            click.echo("Key not found")
            return
        auth_data = {
            "consumer_key": pocket["consumer_key"],
            "code": pocket["code"]
        }
        resp = requests.post(
            "https://getpocket.com/v3/oauth/authorize",
            json=auth_data,
            headers={
                "X-Accept": "application/json",
                "Content-Type": "application/json",
            },
        )
        db.update(
            operations.set("access_token",
                           resp.json()["access_token"]),
            Query().type == "pocket_key",
        )
        click.echo(
            "Successfully completed auth process, you can now run archivy pocket sync to load the data"
        )
예제 #9
0
def test_create_admin_small_password_fails(test_app, cli_runner, click_cli):
    cli_runner.invoke(cli, ["create-admin", "__username__"],
                      input="short\nshort",
                      env={"ARCHIVY_DATA_DIR": test_app.config["APP_PATH"]})
    db = get_db()
    assert not len(
        db.search(Query().type == "user"
                  and Query().username == "__username__"))
예제 #10
0
def sync(force):
    with app.app_context():
        db = get_db()

        # update pocket dictionary
        pocket = db.search(Query().type == "pocket_key")[0]

        pocket_data = {
            "consumer_key": pocket["consumer_key"],
            "access_token": pocket["access_token"],
            "sort": "newest",
        }

        # get date of latest call to pocket api
        since = datetime(1970, 1, 1)
        create_dir("pocket")
        already_saved = set()
        for post in get_items(path="pocket/", structured=False):
            date = datetime.strptime(post["date"].replace("-", "/"), "%x")
            already_saved.add(post["url"])
            since = max(date, since)

        if since != datetime(1970, 1, 1) and not force:
            since = datetime.timestamp(since)
            pocket_data["since"] = since
        bookmarks = requests.post("https://getpocket.com/v3/get",
                                  json=pocket_data).json()

        # api spec: https://getpocket.com/developer/docs/v3/retrieve
        # for some reason, if the `list` attribute is empty it returns a list instead of a dict.
        if not len(bookmarks["list"]):
            click.echo("No new bookmarks.")
        else:
            for pocket_bookmark in bookmarks["list"].values():
                url = pocket_bookmark.get("resolved_url",
                                          pocket_bookmark["given_url"])
                if int(pocket_bookmark["status"]
                       ) != 2 and url not in already_saved:
                    bookmark = DataObj(
                        url=url,
                        date=datetime.now(),
                        type="pocket_bookmark",
                        path="pocket",
                    )
                    try:
                        bookmark.process_bookmark_url()
                        click.echo(f"Saving {bookmark.title}...")
                        bookmark.insert()
                    except:
                        click.echo(
                            f"Could not save {bookmark.url} - website may already be down."
                        )
            click.echo("Done!")
예제 #11
0
파일: routes.py 프로젝트: litanid/archivy
def edit_user():
    form = forms.UserForm()
    if form.validate_on_submit():
        db = get_db()
        db.update(
            {
                "username": form.username.data,
                "hashed_password": generate_password_hash(form.password.data)
            },
            doc_ids=[current_user.id])
        flash("Information saved!", "success")
        return redirect("/")
    form.username.data = current_user.username
    return render_template("users/edit.html", form=form, title="Edit Profile")
예제 #12
0
def login():
    """
    Logs in the API client using
    [HTTP Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication).
    Pass in the username and password of your account.
    """
    db = get_db()
    user = db.search(Query().username == request.authorization["username"])
    if (user and check_password_hash(user[0]["hashed_password"],
                                     request.authorization["password"])):
        # user is verified so we can log him in from the db
        user = User.from_db(user[0])
        login_user(user, remember=True)
        return Response(status=200)
    return Response(status=401)
예제 #13
0
def login():
    form = forms.UserForm()
    if form.validate_on_submit():
        db = get_db()
        user = db.search((Query().username == form.username.data) & (Query().type == "user"))

        if user and check_password_hash(user[0]["hashed_password"], form.password.data):
            user = User.from_db(user[0])
            login_user(user, remember=True)
            flash("Login successful!", "success")

            next_url = request.args.get("next")
            return redirect(next_url or "/")

        flash("Invalid credentials", "error")
        return redirect("/login")
    return render_template("users/login.html", form=form, title="Login")
예제 #14
0
    def insert(self):
        """Inserts the model from the database"""
        if not self.password:
            return False

        hashed_password = generate_password_hash(self.password)
        db = helpers.get_db()

        if db.search((Query().type == "user") & (Query().username == self.username)):
            return False
        db_user = {
            "username": self.username,
            "hashed_password": hashed_password,
            "is_admin": self.is_admin,
            "type": "user",
        }

        helpers.load_hooks().on_user_create(self)
        return db.insert(db_user)
예제 #15
0
파일: test_cli.py 프로젝트: zxhycxq/archivy
def test_initialization(test_app, cli_runner, click_cli):
    conf_path = os.path.join(test_app.config["USER_DIR"], "config.yml")
    try:
        # conf shouldn't exist
        open(conf_path)
        assert False
    except FileNotFoundError:
        pass
    old_data_dir = test_app.config["USER_DIR"]

    with cli_runner.isolated_filesystem():
        # create user, localhost, and don't use ES
        res = cli_runner.invoke(
            click_cli, ["init"],
            input="\nn\ny\nusername\npassword\npassword\n\n")
        assert "Config successfully created" in res.output

        # verify user was created
        assert len(get_db().search(Query().type == "user"
                                   and Query().username == "username"))

        # verify dataobj creation works
        assert DataObj(type="note", title="Test note").insert()
        assert len(get_items(structured=False)) == 1

    conf = open(conf_path).read()

    # assert defaults are saved
    assert "PANDOC_HIGHLIGHT_THEME: pygments" in conf
    assert f"USER_DIR: {test_app.config['USER_DIR']}" in conf
    assert "HOST: 127.0.0.1"
    # check ES config not saved
    assert "ELASTICSEARCH" not in conf

    # check initialization in random directory
    # has resulted in change of user dir
    assert old_data_dir != test_app.config["USER_DIR"]
예제 #16
0
파일: __init__.py 프로젝트: zxhycxq/archivy
def add_metadata(dataobj):
    with app.app_context():
        metadata = get_db().search(Query().type == "metadata")[0]
        dataobj.content += f"Made by {metadata['author']} in {metadata['location']}."
예제 #17
0
파일: __init__.py 프로젝트: zxhycxq/archivy
def load_user(user_id):
    db = helpers.get_db()
    res = db.get(doc_id=int(user_id))
    if res and res["type"] == "user":
        return User.from_db(res)
    return None
예제 #18
0
def test_user_creation_hook(test_app, hooks_cli_runner, user_fixture):
    creation_message = get_db().search(
        Query().type == "user_creation_message")[0]
    assert f"New user {user_fixture.username} created." == creation_message[
        "content"]
예제 #19
0
def test_dataobj_creation_hook(test_app, hooks_cli_runner, note_fixture):
    creation_message = get_db().search(
        Query().type == "dataobj_creation_message")[0]
    assert creation_message[
        "content"] == f"New dataobj on {note_fixture.title} with tags: {note_fixture.tags}"
예제 #20
0
login_manager.login_view = "login"
login_manager.init_app(app)
app.register_blueprint(api_bp, url_prefix='/api')


@login_manager.user_loader
def load_user(user_id):
    db = helpers.get_db()
    res = db.get(doc_id=int(user_id))
    if res and res["type"] == "user":
        return User.from_db(res)
    return None


app.jinja_options["extensions"].append("jinja2.ext.do")

# create admin user if it does not exist
with app.app_context():
    db = helpers.get_db()
    user_query = Query()
    # noqa here because tinydb requires us to explicitly specify is_admin == True
    if not db.search((user_query.type == "user") & (user_query.is_admin == True)): # noqa:
        password = token_urlsafe(32)
        user = User(username="******", password=password, is_admin=True)
        if user.insert():
            app.logger.info(f"""Archivy has created an admin user as it did not exist.
                            Username: '******', password: '******'
                        """)

from archivy import routes  # noqa: