예제 #1
0
    def test_receive_obs_error(self):
        """Test error handling in the receive routine."""

        repository = Repository()
        station_id = 1

        # Check what happens if the path is misconfigured (or the server is not able to write file)
        self.app.root = app.config["storage"][
            'image_root'] = '/nonexistent/path'
        secret = repository.read_station_secret(station_id)

        data = {
            'aos': datetime.datetime(2020, 3, 28, 12, 00),
            'tca': datetime.datetime(2020, 3, 28, 12, 15),
            'los': datetime.datetime(2020, 3, 28, 12, 30),
            'sat': 'NOAA 15',
            # 'notes': optional,
            "file0": open("tests/x.png", 'rb'),
            "file1": open("tests/x.png", 'rb')
        }

        header_value = get_authorization_header_value(str(station_id), secret,
                                                      data)
        headers = {'Authorization': header_value}
        response = self.app.post('/receive', data=data, headers=headers)

        self.assertEqual(response.status_code, 503)

        # Check if there's appropriate entry in the log file.
        self.check_log([
            "Failed to write /nonexistent/path/",
            "tests_x.png (image_root=/nonexistent/path)"
        ])
예제 #2
0
def _get_secret(station_id) -> bytes:
    '''
    Fetch station secret from database

    ToDo: Returned value should be cached to avoid DDoS and
          DB call before authorization
    '''
    repository = Repository()
    return repository.read_station_secret(station_id)
예제 #3
0
파일: login.py 프로젝트: gut-space/svarog
def login():

    repository = Repository()

    if current_user.is_authenticated:
        stations = repository.owned_stations(current_user.get_id())

        # list of stations
        l = " ".join(f"{s['name']}({s['station_id']})" for s in stations)
        app.logger.info("Authenticated user %s, owner of %s" %
                        (current_user.username, l))

        return render_template("login.html",
                               user=current_user,
                               stations=stations)

    form = LoginForm()

    if form.validate_on_submit():
        app.logger.info(
            "Login requested for user %s, pass=%s, remember_me=%s" %
            (form.username.data, form.password.data, form.remember.data))

        user = repository.read_user(user=form.username.data)

        if user is None:
            app.logger.info("Login failed: invalid username: %s" %
                            form.username.data)
            flash("Invalid username.")
            return redirect(url_for("login"))

        u = ApplicationUser(user)
        if not u.check_password(form.password.data):
            app.logger.info("Login failed: invalid password %s for user %s" %
                            (form.password.data, form.username.data))
            flash("Invalid password.")
            return redirect(url_for("login"))

        if u.role == UserRole.BANNED:
            app.logger.info(
                "Login failed: attempt to login into disabled account %s" %
                form.username.data)
            flash("Account disabled.")
            return redirect(url_for("login"))

        app.logger.info("Login successful for user %s" % form.username.data)
        login_user(u, remember=form.remember.data)

        next_page = request.args.get("next")
        if not next_page or url_parse(next_page).netloc != "":
            next_page = url_for("index")
        return redirect(next_page)

    return render_template("login.html", form=form)
예제 #4
0
    def test_db_version(self, mock_connect):
        repostory = Repository({})
        mock_cursor = mock_connect.return_value.cursor.return_value
        mock_cursor.fetchone.side_effect = [{
            "count": 1
        }, (3, ), {
            "version": 15
        }]

        version = repostory.get_database_version()
        self.assertEqual(version, 15)
예제 #5
0
파일: station.py 프로젝트: gut-space/svarog
def station(station_id=None):

    repository = Repository()
    station = repository.read_station(station_id)
    if station is None:
        abort(404, "Station not found")
    statistics = repository.read_station_statistics(station["station_id"])

    photos = repository.read_station_photos(station_id)

    owners = repository.station_owners(station_id)

    # Now get 3 latest observations from this station
    filters = {"station_id": station['station_id']}
    latest_obs = repository.read_observations(filters=filters,
                                              limit=3,
                                              offset=0)

    # Get the 3 observations with the best rating
    best_obs = repository.read_observations(filters=filters,
                                            limit=3,
                                            offset=0,
                                            order="r.rating DESC",
                                            expr="r.rating is not NULL")

    x = {}
    x['station_id'] = station['station_id']
    x['name'] = station['name']
    x['coords'] = utils.coords(station['lon'], station['lat'])
    x['descr'] = station['descr']

    x['config'] = station['config']
    x['registered'] = station['registered']
    x['lastobs'] = statistics["last_los"]
    x['firstobs'] = statistics["first_aos"]
    x['cnt'] = statistics["observation_count"]

    files = []
    for photo in photos:
        y = {}
        y['filename'] = photo['filename']
        y['descr'] = photo['descr']
        y['sort'] = photo['sort']
        files.append(y)

    return render_template('station.html',
                           station=x,
                           files=files,
                           owners=owners,
                           latest_obs=latest_obs,
                           best_obs=best_obs)
예제 #6
0
    def test_receive_obs(self):
        repository = Repository()
        station_id = 1
        secret = repository.read_station_secret(station_id)

        data = {
            'aos':
            datetime.datetime(2020, 3, 28, 12, 00),
            'tca':
            datetime.datetime(2020, 3, 28, 12, 15),
            'los':
            datetime.datetime(2020, 3, 28, 12, 30),
            'sat':
            'NOAA 15',
            'config':
            '{"text":"note text"}',
            "file0":
            open("tests/x.png", 'rb'),
            "file1":
            open("tests/x.png", 'rb'),
            "tle": [
                # Include trailling character
                "1 25544U 98067A   08264.51782528 -.00002182  00000-0 -11606-4 0  2927 ",
                "2 25544  51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537"
            ],
            "rating":
            0.75
        }

        header_value = get_authorization_header_value(str(station_id), secret,
                                                      data)
        headers = {'Authorization': header_value}
        response = self.app.post('/receive', data=data, headers=headers)
        self.assertEqual(response.status_code, 204)
        file_count = lambda dir_: len([
            f for f in os.listdir(dir_)
            if os.path.isfile(os.path.join(dir_, f))
        ])
        self.assertEqual(file_count(IMAGE_ROOT), 2)
        self.assertEqual(file_count(os.path.join(IMAGE_ROOT, "thumbs")), 1)
        chart_dir = os.path.join(IMAGE_ROOT, "charts")
        self.assertEqual(file_count(chart_dir), 2)
        chart_files = sorted(os.listdir(chart_dir))
        self.assertEqual(chart_files, ["by_time-1.png", "polar-1.png"])
        # Todo: Need to check if the DB entries have been added.

        # Check if there are appropriate entries in the log file.
        self.check_log([
            "0-tests_x.png written to tests/images",
            "1-tests_x.png written to tests/images"
        ])
예제 #7
0
파일: obs.py 프로젝트: gut-space/svarog
def obs(obs_id: ObservationId = None, limit_and_offset=None):
    if obs_id is None:
        abort(300, description="ID is required")
        return

    repository = Repository()
    with repository.transaction():
        observation = repository.read_observation(obs_id)

        orbit = None

        if observation is None:
            abort(404, "Observation not found")

        files = repository.read_observation_files(observation["obs_id"],
                                                  **limit_and_offset)
        files_count = repository.count_observation_files(obs_id)
        satellite = repository.read_satellite(observation["sat_id"])

        orbit = observation
        if observation['tle'] is not None:
            # observation['tle'] is always an array of exactly 2 strings.
            orbit = parse_tle(*observation['tle'], satellite["sat_name"])

        station = repository.read_station(observation["station_id"])

    # Now tweak some observation parameters to make them more human readable
    observation = human_readable_obs(observation)

    # Now determine if there is a logged user and if there is, if this user is the owner of this
    # station. If he is, we should show the admin panel.
    user_id = 0
    owner = False
    if current_user.is_authenticated:
        user_id = current_user.get_id()

        # Check if the current user is the owner of the station.
        station_id = station['station_id']

        owner = repository.is_station_owner(user_id, station_id)

    return 'obs.html', dict(obs=observation,
                            files=files,
                            sat_name=satellite["sat_name"],
                            item_count=files_count,
                            orbit=orbit,
                            station=station,
                            is_owner=owner)
예제 #8
0
def migrate(config=None, migration_directory="db"):
    '''
    Perform migrations.

    Parameters
    ==========
    config
        Dictionary with psycopg2 "connect" method arguments.
        If None then read INI file
    migration_directory: str
        Directory with .psql files. Files must to keep naming convention:
            svarog-XX.psql
        where XX is number of database revision.

    Returns
    =======
    Function print migration status on console. Changes are save in database.

    Notes
    =====
    If any migration fail then all changes are revert.
    '''
    repository = Repository(config)

    db_version = repository.get_database_version()

    migrations = list_migrations(migration_directory)

    with repository.transaction() as transaction:
        for migration_version, migration_path in migrations:
            if migration_version <= db_version:
                print("Skip migration to %d version" % (migration_version, ))
                continue

            print("Process migration to %d version..." % (migration_version, ),
                  end="")
            with open(migration_path) as migration_file:
                content = migration_file.read()

            repository.execute_raw_query(content)
            print("OK")

        transaction.commit()

    new_db_version = repository.get_database_version()
    print("Migration complete from %d to %d!" % (db_version, new_db_version))
예제 #9
0
파일: obs.py 프로젝트: gut-space/svarog
def obs_delete(obs_id: ObservationId = None):

    # First check if such an observation even exists.
    repository = Repository()
    observation = repository.read_observation(obs_id)
    if observation is None:
        return render_template('obs_delete.html',
                               status=["There is no observation %s" % obs_id],
                               obs_id=obs_id)

    # Second, check if the guy is logged in.
    if not current_user.is_authenticated:
        return render_template(
            'obs_delete.html',
            status=["You are not logged in, you can't delete anything."],
            obs_id=obs_id)

    # Ok, at least this guy is logged in. Let's check who he is.
    user_id = current_user.get_id()

    # Check if the current user is the owner of the station.
    station = repository.read_station(observation["station_id"])
    station_id = station['station_id']

    owner = repository.is_station_owner(user_id, station_id)

    if not owner:
        return render_template(
            'obs_delete.html',
            status=[
                "You are not the owner of station %s, you can't delete observation %s."
                % (station.name, obs_id)
            ],
            obs_id=obs_id)

    # If you got that far, this means the guy is logged in, he's the owner and is deleting his own observation.

    status = obs_delete_db_and_disk(repository, obs_id)
    return render_template('obs_delete.html', status=status, obs_id=obs_id)
예제 #10
0
파일: obslist.py 프로젝트: gut-space/svarog
def obslist(limit_and_offset, **filters):
    '''This function retrieves observations list from a local database and
        displays it.'''
    aos_before_org = filters.get("aos_before")
    if aos_before_org is not None:
        # Repository uses datetime.datetime structure to bound dates and it is
        # exact date.
        # User provides datetime.date (which not include hour) and it means that
        # list should contain observations from @los_after day 00:00:00 hour to
        # @aos_before day 23:59:59.999 hour. For handle it we add 1 day to
        # @aos_before day before send to repository.
        filters["aos_before"] = aos_before_org + timedelta(days=1)

    repository = Repository()
    obslist = repository.read_observations(filters, **limit_and_offset)
    satellites_list = repository.read_satellites()
    observation_count = repository.count_observations(filters)
    stations_list = repository.read_stations()

    satellites_dict = {
        sat["sat_id"]: sat["sat_name"]
        for sat in satellites_list
    }
    stations_dict = {s["station_id"]: s["name"] for s in stations_list}
    for obs in obslist:
        obs["sat_name"] = satellites_dict[obs["sat_id"]]
        obs["station_name"] = stations_dict[obs["station_id"]]

    if aos_before_org is not None:
        # We send back to user the same date as user provide.
        filters["aos_before"] = aos_before_org

    # When database will contain many satellites and stations then we need
    # refactor this code to lazy, async read satellites and stations.
    return 'obslist.html', dict(obslist=obslist,
                                item_count=observation_count,
                                satellites=satellites_list,
                                stations=stations_list,
                                filters=filters)
예제 #11
0
def stations(limit_and_offset):
    '''This function retrieves list of all registered ground stations.'''
    repository = Repository()
    stations = repository.read_stations(**limit_and_offset)
    statistics = repository.read_stations_statistics(**limit_and_offset)
    station_count = repository.count_stations()
    # Now convert the data to a list of objects that we can pass to the template.
    stationlist = []

    for station, stat in zip(stations, statistics):
        x = {}
        x['station_id'] = station['station_id']
        x['name'] = station['name']
        x['coords'] = utils.coords(station['lon'], station['lat'])
        x['descr'] = station['descr']
        x['config'] = station['config']
        x['registered'] = station['registered']
        x['lastobs'] = stat["last_los"]
        x['cnt'] = stat["observation_count"]

        stationlist.append(x)

    return 'stations.html', dict(stations=stationlist,
                                 item_count=station_count)
예제 #12
0
파일: login.py 프로젝트: gut-space/svarog
def load_user(user_id):
    rep = Repository()
    u = rep.read_user(user=user_id)
    if u:
        return ApplicationUser(u)
    return None
from flask import render_template, flash, redirect
from app import app

from app.forms import AddTaskForm
from app.usecases import AddTaskCase
from app.repository import Repository

repo = Repository()


@app.route("/", methods=['GET', 'POST'])
def index():
    add_task = AddTaskCase()
    add_task.repo = repo
    form = AddTaskForm()

    all_tasks = repo.get_all_tasks()

    if form.validate_on_submit():
        result = add_task.create(
            header=form.header.data,
            body=form.body.data,
            done=form.done.data,
        )
        flash(f"Task created : {result}")
        return redirect("/")
    return render_template("home.html", form=form, tasks=all_tasks)
예제 #14
0
import string

from app.pieces import Color, Empty, Pawn, Rook, Knight, Bishop, Queen, King
from app.position import Position
from app.repository import Repository

POSITIONS_DELIMITER = ':'  # Символ для розмежування позицій в рамках ходу збереженої гри
MOVEMENTS_DELIMITER = '#'  # Символ для розмежування ходів в рамках збереженої гри

repository = Repository()  # Об'єкт типу Repository для виклику методів класу Repository для роботи з базою даних


class Chessboard(object):  # Клас Chessboard який наслідує object

    def __init__(self):  # Метод ініціалізації початкових значень для об'єкта класа Chessboard
        self.movements_history = []  # Історія ходів для подальшого збереження гри
        self.current_player_color = Color.WHITE  # Колір поточного гравця
        self.captured_white_pieces = []  # Фігури, побиті чорними
        self.captured_black_pieces = []  # Фігури, побиті білими
        self.board = [  # Встановлення фігур на початкові позиції
            [Rook(Color.WHITE), Pawn(Color.WHITE), Empty(), Empty(), Empty(), Empty(), Pawn(Color.BLACK), Rook(Color.BLACK)],
            [Knight(Color.WHITE), Pawn(Color.WHITE), Empty(), Empty(), Empty(), Empty(), Pawn(Color.BLACK), Knight(Color.BLACK)],
            [Bishop(Color.WHITE), Pawn(Color.WHITE), Empty(), Empty(), Empty(), Empty(), Pawn(Color.BLACK), Bishop(Color.BLACK)],
            [Queen(Color.WHITE), Pawn(Color.WHITE), Empty(), Empty(), Empty(), Empty(), Pawn(Color.BLACK), Queen(Color.BLACK)],
            [King(Color.WHITE), Pawn(Color.WHITE), Empty(), Empty(), Empty(), Empty(), Pawn(Color.BLACK), King(Color.BLACK)],
            [Bishop(Color.WHITE), Pawn(Color.WHITE), Empty(), Empty(), Empty(), Empty(), Pawn(Color.BLACK), Bishop(Color.BLACK)],
            [Knight(Color.WHITE), Pawn(Color.WHITE), Empty(), Empty(), Empty(), Empty(), Pawn(Color.BLACK), Knight(Color.BLACK)],
            [Rook(Color.WHITE), Pawn(Color.WHITE), Empty(), Empty(), Empty(), Empty(), Pawn(Color.BLACK), Rook(Color.BLACK)]
        ]

    # Метод для перевірки, чи може поточний гравець походити даною фігурою
예제 #15
0
 def __init__(self, repo_client=Repository(adapter=adapter)):
     self.client = repo_client
예제 #16
0
# This script generates fly-over charts for observations that have TLE
# information recorded.

from typing import Dict
from app.controllers.receive import make_charts
from app.repository import Repository, Station, StationId

if __name__ == '__main__':
    stations: Dict[StationId, Station] = { }

    repository = Repository()
    observation_count = repository.count_observations()

    print("There are a total of %d observations" % observation_count)

    STEP = 100
    limit = STEP
    offset = 0
    index = 0

    while offset < observation_count:
        # ToDo: Add filtration when MR with filtration will be merged.
        observations = repository.read_observations(limit=limit, offset=offset)

        print("Processing batch of %d observations" % len(observations))

        for observation in observations:
            if observation['tle'] is None:
                print("No TLE info for observation %d, skipping." % observation['obs_id'])
                continue
            station_id = observation["station_id"]
예제 #17
0
 def __init__(self,repo_client=Repository(adapter=MongoRepository)):
   self.repo_client = repo_client
예제 #18
0
파일: server.py 프로젝트: ykhilaji/Samples
 def initialize(self):
     self.repository = Repository()
예제 #19
0
 def wrapper(self, *args, **kwargs):
     config = self.db_config
     repository = Repository(config)
     return f(self, repository, *args, **kwargs)
예제 #20
0
파일: service.py 프로젝트: ykhilaji/Samples
 def __init__(self):
     self.repository = Repository()
예제 #21
0
파일: receive.py 프로젝트: gut-space/svarog
def receive(station_id: str, args: RequestArguments):
    '''
    Receive observation from station.

    Station must be authenticated.

    Request must have attached at least one imagery file. We accept only files
    with MIME-type and extension listed in @ALLOWED_FILE_TYPES dictionary.

    From first imagery file we create a thumbnail. Files are sorted using HTTP
    request keys.

    Request data are stored in DB. Binary files are saved in filesystem with
    unique, conflict-safe filename.

    Satellite assigned to observation must exists in database.
    '''

    files: Dict[str, WebFileLike] = request.files

    if len(files) == 0:
        abort(400, description="Missing file")

    # Filter files and create safe filenames
    uid = str(uuid.uuid4())
    items = enumerate(sorted(files.items(), key=lambda e: e[0]))
    file_entries: List[Tuple[str, WebFileLike]] = []
    for idx, (_, file_) in items:
        if not is_allowed_file(file_):
            app.logger.warning(
                f"File {file_.filename} is not allowed due to its type ({file_.mimetype}) or extension"
            )
            continue
        org_filename = secure_filename(file_.filename)
        filename = "%s-%d-%s" % (uid, idx, org_filename)
        file_entries.append((filename, file_))
        app.logger.info(
            f"Received file {file_.filename}, to be stored as {filename}")

    # Select thumbnail source file
    thumbnail_source_entry = first(
        lambda f: f[1].mimetype.startswith("image/"), file_entries)
    if thumbnail_source_entry is None:
        app.logger.info(f"No suitable images for thumbnail, using None")
        thumb_filename = None
    else:
        thumb_source_filename, _ = thumbnail_source_entry
        thumb_filename = "thumb-%s-%s" % (str(
            uuid.uuid4()), thumb_source_filename)

    # Save data in DB
    repository = Repository()
    with repository.transaction() as transaction:
        satellite = repository.read_satellite(args["sat"])
        if satellite is None:
            abort(400, description="Unknown satellite")

        sat_id = SatelliteId(satellite["sat_id"])

        tle = args.get('tle')
        if tle:
            # Remove trailing character
            tle = [line.strip() for line in tle]

        # Let's get metadata and try to run some sanity checks on it. Technically the whole thing
        # is not mandatory, so we only complain if important parameters are missing, but we
        # accept the observation anyway.
        metadata = args.get('config') or "{}"
        mandatory_tags = [
            "protocol", "frequency", "antenna", "antenna-type", "receiver",
            "lna", "filter"
        ]
        missing = []
        for t in mandatory_tags:
            if t not in metadata:
                missing.append(t)
        if len(missing):
            app.logger.warning(
                f"Received observation from station {station_id} with missing tags: {' '.join(missing)}"
            )

        observation: Observation = {
            'obs_id': ObservationId(0),
            'aos': args['aos'],
            'tca': args['tca'],
            'los': args['los'],
            'sat_id': sat_id,
            'thumbnail': thumb_filename,
            'config': metadata,
            'station_id': StationId(station_id),
            'tle': tle
        }

        app.logger.info(
            "Received observation: station_id=%s sat_id=%s config=%s rating=%s"
            % (station_id, sat_id, args.get('config'), args.get('rating')))

        obs_id = repository.insert_observation(observation)
        observation["obs_id"] = obs_id

        for filename, file_ in file_entries:
            observation_file: ObservationFile = {
                "obs_file_id": ObservationFileId(0),
                "filename": filename,
                "media_type": file_.mimetype,
                "obs_id": obs_id,
                'rating': args.get('rating')
            }
            repository.insert_observation_file(observation_file)

        transaction.commit()

    # Save files in filesystem
    root = app.config["storage"]['image_root']

    for filename, file_ in file_entries:
        path = os.path.join(root, filename)
        try:
            file_.save(path)
            app.logger.info("File %s written to %s" % (filename, root))
        except OSError as e:
            app.logger.error("Failed to write %s (image_root=%s): %s" %
                             (path, root, e))
            return abort(
                503,
                "Unable to write file %s. Disk operation error." % filename)

    if thumb_filename != None:
        # Make thumbnail (but only if suitable images were submitted, for text we're out of luck)
        thumb_source_path = os.path.join(root, thumb_source_filename)
        thumb_path = os.path.join(root, "thumbs", thumb_filename)
        app.logger.debug(f"Generating thumbnail for {thumb_source_filename}.")
        make_thumbnail(thumb_source_path, thumb_path)

    # Make charts
    station = repository.read_station(observation["station_id"])
    make_charts(observation, station, root)

    # Make sure to return the observation id to the station. This may be useful if the station wants
    # to update the observation in some way (send additional info or perhaps decide to delete it in the future).
    return 'Observation %d received.' % obs_id, 204