src/web/packages.py \
src/web/repos.py \
src/web/search.py \
+ src/web/sources.py \
src/web/ui_modules.py \
src/web/uploads.py \
src/web/users.py
templates_repos_modulesdir = $(templates_reposdir)/modules
+dist_templates_sources_DATA = \
+ src/templates/sources/show.html
+
+templates_sourcesdir = $(templatesdir)/sources
+
+dist_templates_sources_modules_DATA = \
+ src/templates/sources/modules/list.html
+
+templates_sources_modulesdir = $(templates_sourcesdir)/modules
+
dist_templates_packages_DATA = \
src/templates/packages/index.html \
src/templates/packages/name.html \
return repo
- @lazy_property
- def sources(self):
- _sources = []
+ # Builds
- for source in self.db.query("SELECT id FROM sources WHERE distro_id = %s", self.id):
- source = sources.Source(self.pakfire, source.id)
- _sources.append(source)
+ def get_builds_by_name(self, name, limit=None):
+ """
+ Returns all builds that match the name
+ """
+ builds = self.backend.builds._get_builds("""
+ SELECT
+ builds.*
+ FROM
+ repositories
+ LEFT JOIN
+ repository_builds ON repositories.id = repository_builds.repo_id
+ LEFT JOIN
+ builds ON repository_builds.build_id = builds.id
+ LEFT JOIN
+ packages ON builds.pkg_id = packages.id
+ WHERE
+ repositories.deleted IS TRUE
+ AND
+ repositories.distro_id = %s
+ AND
+ repository_builds.removed_at IS NULL
+ AND
+ builds.deleted_at IS NULL
+ AND
+ packages.name = %s
+ ORDER BY
+ created_at DESC
+ LIMIT
+ %s
+ """, self.id, name, limit,
+ )
- return sorted(_sources)
+ return builds
- def get_source(self, identifier):
- for source in self.sources:
- if not source.identifier == identifier:
- continue
+ @lazy_property
+ def sources(self):
+ sources = self.backend.sources._get_sources("""
+ SELECT
+ sources.*
+ FROM
+ sources
+ LEFT JOIN
+ repositories ON sources.repo_id = repositories.id
+ WHERE
+ repositories.distro_id = %s
+ ORDER BY
+ sources.name, sources.url
+ """, self.id,
+ )
- return source
+ return list(sources)
return list(sources)
+ def get_source_by_slug(self, slug):
+ return self.backend.sources._get_source("""
+ SELECT
+ *
+ FROM
+ sources
+ WHERE
+ deleted_at IS NULL
+ AND
+ repo_id = %s
+ AND
+ slug = %s
+ """, self.id, slug,
+
+ # Prefill cache
+ repo=self,
+ )
+
async def fetch_sources(self):
"""
Fetches all sources for this repository
)
class Sources(base.Object):
- def _get_sources(self, query, *args):
- res = self.db.query(query, *args)
-
- for row in res:
- yield Source(self.backend, row.id, data=row)
-
- def _get_source(self, query, *args):
- res = self.db.get(query, *args)
+ def _get_sources(self, query, *args, **kwargs):
+ return self.db.fetch_many(Source, query, *args, **kwargs)
- if res:
- return Source(self.backend, res.id, data=res)
+ def _get_source(self, query, *args, **kwargs):
+ return self.db.fetch_one(Source, query, *args, **kwargs)
def get_by_id(self, id):
return self._get_source("""
def slug(self):
return self.data.slug
+ @property
+ def distro(self):
+ return self.repo.distro
+
# Repo
@lazy_property
</div>
</section>
{% end %}
+
+ {# Sources #}
+
+ {% if distro.sources %}
+ <section class="section">
+ <div class="container">
+ <h4 class="title is-4">{{ _("Sources") }}</h4>
+
+ {% module SourcesList(distro.sources) %}
+ </div>
+ </section>
+ {% end %}
{% end block %}
--- /dev/null
+<div class="block">
+ <nav class="panel is-link">
+ {% for source in sources %}
+ <a class="panel-block is-justify-content-space-between p-4" href="{{ source.repo.url }}/sources/{{ source.slug }}">
+ <h5 class="title is-5">
+ {{ source }}
+ </h5>
+ </a>
+ {% end %}
+ </nav>
+</div>
--- /dev/null
+{% extends "../base.html" %}
+
+{% block title %}{{ _("Source") }} - {{ source }}{% end block %}
+
+{% block body %}
+ <section class="hero is-light">
+ <div class="hero-body">
+ <div class="container">
+ <nav class="breadcrumb" aria-label="breadcrumbs">
+ <ul>
+ {% if source.repo.owner %}
+ <li>
+ <a href="/users">{{ _("Users") }}</a>
+ </li>
+ <li>
+ <a href="/users/{{ source.repo.owner.name }}">{{ source.repo.owner }}</a>
+ </li>
+ <li>
+ <a href="#" disabled>{{ _("Distributions") }}</a>
+ </li>
+ <li>
+ <a href="#" disabled>{{ source.distro }}</a>
+ </li>
+ {% else %}
+ <li>
+ <a href="/distros">{{ _("Distributions") }}</a>
+ </li>
+ <li>
+ <a href="/distros/{{ source.distro.slug }}">{{ source.distro }}</a>
+ </li>
+ {% end %}
+ <li>
+ <a href="#" disabled>{{ _("Repositories") }}</a>
+ </li>
+ <li>
+ <a href="{{ source.repo.url }}" aria-current="page">{{ source.repo }}</a>
+ </li>
+ <li>
+ <a href="#" disabled>{{ _("Sources") }}</a>
+ </li>
+ <li class="is-active">
+ <a href="#" aria-current="page">{{ source }}</a>
+ </li>
+ </ul>
+ </nav>
+
+ <h1 class="title is-1">{{ source }}</h1>
+ </div>
+ </div>
+ </section>
+{% end block %}
from . import packages
from . import repos
from . import search
+from . import sources
from . import uploads
from . import users
from .handlers import *
# Repositories
"ReposList" : repos.ListModule,
+ # Sources
+ "SourcesList" : sources.ListModule,
+
# Users
"UsersList" : users.ListModule,
"UserPushSubscribeButton" : users.PushSubscribeButton,
repos.EditHandler),
(r"/users/(?P<user_slug>\w+)/repos/(?P<distro_slug>[A-Za-z0-9\-\.]+)/(?P<repo_slug>[A-Za-z0-9\-]+)/mirrorlist",
repos.MirrorlistHandler),
+ (r"/users/(?P<user_slug>\w+)/repos/(?P<distro_slug>[A-Za-z0-9\-\.]+)/(?P<repo_slug>[A-Za-z0-9\-]+)/sources/(?P<source_slug>[A-Za-z0-9\-]+)",
+ sources.ShowHandler),
# Packages
(r"/packages", packages.IndexHandler),
repos.EditHandler),
(r"/distros/(?P<distro_slug>[A-Za-z0-9\-\.]+)/repos/(?P<repo_slug>[A-Za-z0-9\-]+)/mirrorlist",
repos.MirrorlistHandler),
+ (r"/distros/(?P<distro_slug>[A-Za-z0-9\-\.]+)/repos/(?P<repo_slug>[A-Za-z0-9\-]+)/sources/(?P<source_slug>[A-Za-z0-9\-]+)",
+ sources.ShowHandler),
# Mirrors
(r"/mirrors", mirrors.IndexHandler),
--- /dev/null
+###############################################################################
+# #
+# Pakfire - The IPFire package management system #
+# Copyright (C) 2022 Pakfire development team #
+# #
+# 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 <http://www.gnu.org/licenses/>. #
+# #
+###############################################################################
+
+from . import base
+from . import ui_modules
+
+class ShowHandler(base.BaseHandler):
+ def _get_source(self, distro_slug, repo_slug, source_slug, user_slug=None):
+ user = None
+
+ # Find the user
+ if user_slug:
+ user = self.backend.users.get_by_name(user_slug)
+ if not user:
+ raise tornado.web.HTTPError(404, "Could not find user: %s" % user_slug)
+
+ # Find the distribution
+ distro = self.backend.distros.get_by_slug(distro_slug)
+ if not distro:
+ raise tornado.web.HTTPError(404, "Could not find distro: %s" % distro_slug)
+
+ # Find the repository
+ if user:
+ repo = user.get_repo(distro, repo_slug)
+ else:
+ repo = distro.get_repo(repo_slug)
+ if not repo:
+ raise tornado.web.HTTPError(404, "Could not find repo: %s" % repo_slug)
+
+ # Find the source
+ source = repo.get_source_by_slug(source_slug)
+ if not source:
+ raise tornado.web.HTTPError(404, "Could not find source: %s" % source_slug)
+
+ return source
+
+ def get(self, **kwargs):
+ source = self._get_source(**kwargs)
+
+ self.render("sources/show.html", source=source)
+
+
+class ListModule(ui_modules.UIModule):
+ def render(self, sources):
+ return self.render_string("sources/modules/list.html", sources=sources)