def __iter__(self):
builders = self._get_builders("SELECT * FROM builders \
- WHERE deleted IS FALSE ORDER BY name")
+ WHERE deleted_at IS NULL ORDER BY name")
return iter(builders)
def get_by_name(self, name):
return self._get_builder("SELECT * FROM builders \
- WHERE name = %s AND deleted IS FALSE", name)
+ WHERE name = %s AND deleted_at IS NULL", name)
@property
def connected(self):
# Otherwise return a neutral preference
return 0
+ # Delete
+
+ def delete(self, user=None):
+ """
+ Deletes this builder
+ """
+ log.info("Deleted builder %s" % self)
+
+ self._set_attribute_now("deleted_at")
+ if user:
+ self._set_attribute("deleted_by", user)
+
# Stats
@lazy_property
name text NOT NULL,
description text,
enabled boolean DEFAULT false NOT NULL,
- deleted boolean DEFAULT false NOT NULL,
loadavg text DEFAULT '0'::character varying NOT NULL,
maintenance boolean DEFAULT false NOT NULL,
max_jobs bigint DEFAULT (1)::bigint NOT NULL,
cpu_model text,
cpu_count integer DEFAULT 1 NOT NULL,
host_key_id text,
- time_created timestamp without time zone DEFAULT now() NOT NULL,
updated_at timestamp without time zone,
- time_keepalive timestamp without time zone,
- online_until timestamp without time zone,
cpu_arch text,
instance_id text,
instance_type text,
- mem_total bigint
+ mem_total bigint,
+ created_at timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
+ created_by integer,
+ deleted_at timestamp without time zone,
+ deleted_by integer
);
-- Name: builders_name; Type: INDEX; Schema: public; Owner: -
--
-CREATE UNIQUE INDEX builders_name ON public.builders USING btree (name) WHERE (deleted IS FALSE);
+CREATE UNIQUE INDEX builders_name ON public.builders USING btree (name) WHERE (deleted_at IS NULL);
--
ADD CONSTRAINT builder_stats_builder_id FOREIGN KEY (builder_id) REFERENCES public.builders(id);
+--
+-- Name: builders builders_created_by; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.builders
+ ADD CONSTRAINT builders_created_by FOREIGN KEY (created_by) REFERENCES public.users(id);
+
+
+--
+-- Name: builders builders_deleted_by; Type: FK CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.builders
+ ADD CONSTRAINT builders_deleted_by FOREIGN KEY (deleted_by) REFERENCES public.users(id);
+
+
--
-- Name: builds builds_build_group_id; Type: FK CONSTRAINT; Schema: public; Owner: -
--
-{% extends "../base.html" %}
+{% extends "../modal.html" %}
-{% block title %}{{ _("Delete builder %s") % builder.name }}{% end block %}
+{% block title %}{{ _("Delete Builder") }} - {{ builder }}{% end block %}
-{% block body %}
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <nav aria-label="breadcrumb" role="navigation">
- <ol class="breadcrumb">
- <li class="breadcrumb-item"><a href="/">{{ _("Home") }}</a></li>
- <li class="breadcrumb-item"><a href="/builders">{{ _("Builders") }}</a></li>
- <li class="breadcrumb-item"><a href="/builders/{{ builder.name }}">{{ builder.name }}</a></li>
- <li class="breadcrumb-item active">
- <a href="/builders/{{ builder.name }}/delete">{{ _("Delete") }}</a>
- </li>
- </ol>
- </nav>
- </div>
- </div>
+{% block breadcrumbs %}
+ <nav class="breadcrumb" aria-label="breadcrumbs">
+ <ul>
+ <li>
+ <a href="/builders">{{ _("Builders") }}</a>
+ </li>
+ <li>
+ <a href="/builders/{{ builder.hostname }}">{{ builder }}</a>
+ </li>
+ <li class="is-active">
+ <a href="#" aria-current="page">{{ _("Delete") }}</a>
+ </li>
+ </ul>
+ </nav>
+{% end block %}
+
+{% block modal_title %}
+ <h4 class="title is-4">{{ _("Delete Builder") }}</h4>
+ <h6 class="subtitle is-6">{{ builder }}</h6>
+{% end block %}
+
+{% block modal %}
+ <form method="POST" action="">
+ {% raw xsrf_form_html() %}
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <div class="alert alert-danger" role="alert">
- <h2 class="alert-heading" style="word-wrap: break-word;">
- {{ _("Delete builder: %s") % builder.name }}
- </h2>
- <p>
- {{ _("You are going to delete the build host %s.") % builder.name }}
- </p>
- </div>
+ <div class="content">
+ <p>
+ {{ _("Are you sure you want to delete %s?") % builder }}
+ </p>
</div>
- </div>
- <div class="row">
- <div class="col-12 col-sm-12 col-md-12 col-lg-12 col-xl-12">
- <div class="btn-toolbar" role="toolbar">
- <div class="btn-group mr-2 mb-2" role="group">
- <a class="btn btn-danger" href="/builders/{{ builder.name }}/delete?confirmed=1">
- {{ _("Delete %s") % builder.name }}
- </a>
- </div>
- <div class="btn-group mb-2" role="group">
- <a class="btn btn-primary" href="/builders/{{ builder.name }}">{{ _("Cancel") }}</a>
- </div>
- </div>
+ {# Submit! #}
+ <div class="field">
+ <button type="submit" class="button is-danger is-fullwidth">
+ {{ _("Delete") }}
+ </button>
</div>
- </div>
+ </form>
{% end block %}
<a class="button is-warning" href="/builders/{{ builder.hostname }}/edit">
{{ _("Edit") }}
</a>
+
+ <a class="button is-danger" href="/builders/{{ builder.hostname }}/delete">
+ {{ _("Delete") }}
+ </a>
</div>
</section>
{% end %}
(r"/builders", builders.IndexHandler),
(r"/builders/create", builders.CreateHandler),
(r"/builders/([A-Za-z0-9\-\.]+)", builders.ShowHandler),
- (r"/builders/([A-Za-z0-9\-\.]+)/delete", builders.BuilderDeleteHandler),
+ (r"/builders/([A-Za-z0-9\-\.]+)/delete", builders.DeleteHandler),
(r"/builders/([A-Za-z0-9\-\.]+)/edit", builders.BuilderEditHandler),
(r"/builders/([A-Za-z0-9\-\.]+)/stats", builders.StatsHandler),
(r"/api/v1/builders/control", builders.APIv1ControlHandler),
self.redirect("/builders/%s" % builder.hostname)
-class BuilderDeleteHandler(base.BaseHandler):
+class DeleteHandler(base.BaseHandler):
@tornado.web.authenticated
def get(self, name):
builder = self.backend.builders.get_by_name(name)
if not builder.has_perm(self.current_user):
raise tornado.web.HTTPError(403)
- confirmed = self.get_argument("confirmed", None)
- if confirmed:
- with self.db.transaction():
- builder.deleted = True
+ self.render("builders/delete.html", builder=builder)
- self.redirect("/builders")
- return
+ @tornado.web.authenticated
+ async def post(self, hostname):
+ builder = self.backend.builders.get_by_name(hostname)
+ if not builder:
+ raise tornado.web.HTTPError(404, "Builder not found: %s" % hostname)
- self.render("builders/delete.html", builder=builder)
+ # Check permissions
+ if not builder.has_perm(self.current_user):
+ raise tornado.web.HTTPError(403)
+
+ # Delete the builder
+ with self.db.transaction():
+ builder.delete(user=self.current_user)
+
+ self.redirect("/builders")
class StatsModule(ui_modules.UIModule):