From: Michael Tremer Date: Wed, 22 Jun 2022 16:10:07 +0000 (+0000) Subject: repositories: Add option to create personal repositories X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f87d64a23c1575e4589903194427a7306d2f9617;p=pbs.git repositories: Add option to create personal repositories Signed-off-by: Michael Tremer --- diff --git a/src/buildservice/misc.py b/src/buildservice/misc.py index c491da69..0db857c6 100644 --- a/src/buildservice/misc.py +++ b/src/buildservice/misc.py @@ -6,6 +6,7 @@ import random import re import string import tarfile +import unicodedata from .constants import * @@ -18,6 +19,34 @@ def generate_random_string(length=16): """ return "".join([random.choice(random_chars) for i in range(length)]) +def infinity(): + i = 0 + + while True: + i += 1 + yield i + +def normalize(*args, iteration=1): + s = "-".join((e for e in args if e)) + + # Append iteration when larger than one + if iteration > 1: + s += "-%s" % iteration + + # Remove any non-ASCII characters + try: + s = unicodedata.normalize("NFKD", s) + except TypeError: + pass + + # Encode into ASCII and back again + s = s.encode("ascii", errors="ignore").decode() + + # Remove excessive whitespace + s = re.sub(r"[^\w]+", " ", s) + + return "-".join(s.split()) + def format_size(s): units = ("B", "k", "M", "G", "T") diff --git a/src/buildservice/repository.py b/src/buildservice/repository.py index ef2dadcb..2b3e79aa 100644 --- a/src/buildservice/repository.py +++ b/src/buildservice/repository.py @@ -10,6 +10,7 @@ log.propagate = 1 from . import base from . import logs +from . import misc from .constants import * from .decorators import * @@ -33,9 +34,44 @@ class Repositories(base.Object): return iter(repositories) - def create(self, distro, name, description): - return self._get_repository("INSERT INTO repositories(distro_id, name, description) \ - VALUES(%s, %s, %s) RETURNING *", distro.id, name, description) + def create(self, distro, name, owner=None): + """ + Creates a new repository + """ + # Generate a slug + slug = self._make_slug(name, owner=owner) + + return self._get_repository(""" + INSERT INTO + repositories + ( + distro_id, + owner_id, + name, + slug + ) + VALUES + ( + %s, + %s, + %s, + %s + ) + RETURNING *""", + distro, + owner, + name, + slug, + ) + + def _make_slug(self, name, owner=None): + for i in misc.infinity(): + slug = misc.normalize(name) + + exists = self.db.get("SELECT 1 FROM repositories \ + WHERE deleted IS FALSE AND owner_id = %s AND slug = %s", owner, slug) + if not exists: + return slug def get_by_id(self, repo_id): return self._get_repository("SELECT * FROM repositories \ @@ -132,14 +168,16 @@ class Repository(base.DataObject): priority = property(lambda s: s.data.priority, set_priority) - def get_user(self): - if self.data.user_id: - return self.backend.users.get_by_id(self.data.user_id) + # Owner - def set_user(self, user): - self._set_attribute("user_id", user.id) + def get_owner(self): + if self.data.owner_id: + return self.backend.users.get_by_id(self.data.owner_id) - user = property(get_user, set_user) + def set_owner(self, owner): + self._set_attribute("owner_id", owner) + + owner = property(get_owner, set_owner) @property def info(self): @@ -150,31 +188,37 @@ class Repository(base.DataObject): "arches" : self.arches, } - @property - def basepath(self): - return os.path.join( - self.distro.identifier, - self.identifier, + @lazy_property + def path(self): + parts = [] + + # Add owner + if self.owner: + parts.append("~%s" % self.owner.name) + + # Add distro & slug + parts += ( + self.distro.sname, + self.slug, ) - @property - def path(self): - return os.path.join(REPOS_DIR, self.basepath) + # Join everything together + return os.path.join(*parts) @property def url(self): return "/".join(( self.settings.get("baseurl", "https://pakfire.ipfire.org"), "repositories", - self.basepath, + self.path, )) @property def mirrorlist(self): return "/".join(( self.settings.get("baseurl", "https://pakfire.ipfire.org"), - "distro", self.distro.identifier, - "repo", self.identifier, + "distro", self.distro.sname, + "repo", self.slug, "mirrorlist?arch=%{arch}" )) @@ -198,14 +242,6 @@ class Repository(base.DataObject): def name(self): return self.data.name - @property - def identifier(self): - return self.name.lower() - - @property - def type(self): - return self.data.type - @property def summary(self): lines = self.description.splitlines() diff --git a/src/buildservice/users.py b/src/buildservice/users.py index 63a603d0..00af8a1f 100644 --- a/src/buildservice/users.py +++ b/src/buildservice/users.py @@ -369,6 +369,29 @@ class User(base.DataObject): return self.backend.sessions._get_sessions("SELECT * FROM sessions \ WHERE user_id = %s AND valid_until >= NOW() ORDER BY created_at") + # Custom repositories + + @property + def repos(self): + """ + Returns all custom repositories + """ + repos = self.backend.repositories._get_repos(""" + SELECT + * + FROM + repositories + WHERE + deleted IS FALSE + AND + owner_id = %s + ORDER BY + name""", + self.id, + ) + + return list(repos) + class UserEmail(base.DataObject): table = "users_emails" diff --git a/src/database.sql b/src/database.sql index 9248b030..68aaf757 100644 --- a/src/database.sql +++ b/src/database.sql @@ -1086,7 +1086,7 @@ ALTER TABLE public.relation_sizes OWNER TO pakfire; CREATE TABLE public.repositories ( id integer NOT NULL, name text NOT NULL, - type text DEFAULT 'testing'::text NOT NULL, + slug text, description text NOT NULL, distro_id integer NOT NULL, parent_id integer, @@ -1099,8 +1099,10 @@ CREATE TABLE public.repositories ( time_max integer DEFAULT 0 NOT NULL, deleted boolean DEFAULT false NOT NULL, priority integer, - user_id integer, - update_forced boolean DEFAULT false NOT NULL + owner_id integer, + update_forced boolean DEFAULT false NOT NULL, + created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL, + listed boolean DEFAULT true NOT NULL ); @@ -1883,14 +1885,6 @@ ALTER TABLE ONLY public.queue_delete ADD CONSTRAINT idx_2198155_primary PRIMARY KEY (id); --- --- Name: repositories idx_2198164_primary; Type: CONSTRAINT; Schema: public; Owner: pakfire --- - -ALTER TABLE ONLY public.repositories - ADD CONSTRAINT idx_2198164_primary PRIMARY KEY (id); - - -- -- Name: repositories_aux idx_2198179_primary; Type: CONSTRAINT; Schema: public; Owner: pakfire -- @@ -1987,6 +1981,14 @@ ALTER TABLE ONLY public.repositories_builds ADD CONSTRAINT repositories_builds_unique UNIQUE (repo_id, build_id); +-- +-- Name: repositories repositories_pkey; Type: CONSTRAINT; Schema: public; Owner: pakfire +-- + +ALTER TABLE ONLY public.repositories + ADD CONSTRAINT repositories_pkey PRIMARY KEY (id); + + -- -- Name: sessions sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: pakfire -- @@ -2305,6 +2307,13 @@ CREATE INDEX packages_src_created_at ON public.packages USING btree (created_at CREATE INDEX repositories_builds_repo_id ON public.repositories_builds USING btree (repo_id); +-- +-- Name: repositories_unique; Type: INDEX; Schema: public; Owner: pakfire +-- + +CREATE UNIQUE INDEX repositories_unique ON public.repositories USING btree (owner_id, distro_id, name) WHERE (deleted IS FALSE); + + -- -- Name: uploads_uuid; Type: INDEX; Schema: public; Owner: pakfire -- @@ -2656,19 +2665,19 @@ ALTER TABLE ONLY public.repositories -- --- Name: repositories repositories_parent_id; Type: FK CONSTRAINT; Schema: public; Owner: pakfire +-- Name: repositories repositories_owner_id; Type: FK CONSTRAINT; Schema: public; Owner: pakfire -- ALTER TABLE ONLY public.repositories - ADD CONSTRAINT repositories_parent_id FOREIGN KEY (parent_id) REFERENCES public.repositories(id); + ADD CONSTRAINT repositories_owner_id FOREIGN KEY (owner_id) REFERENCES public.users(id); -- --- Name: repositories repositories_user_id; Type: FK CONSTRAINT; Schema: public; Owner: pakfire +-- Name: repositories repositories_parent_id; Type: FK CONSTRAINT; Schema: public; Owner: pakfire -- ALTER TABLE ONLY public.repositories - ADD CONSTRAINT repositories_user_id FOREIGN KEY (user_id) REFERENCES public.users(id); + ADD CONSTRAINT repositories_parent_id FOREIGN KEY (parent_id) REFERENCES public.repositories(id); --