|replication_desired|number|Minimum storage replication level desired for each data block referenced by this collection. A value of @null@ signifies that the site default replication level (typically 2) is desired.|@2@|
|replication_confirmed|number|Replication level most recently confirmed by the storage system. This field is null when a collection is first created, and is reset to null when the manifest_text changes in a way that introduces a new data block. An integer value indicates the replication level of the _least replicated_ data block in the collection.|@2@, null|
|replication_confirmed_at|datetime|When replication_confirmed was confirmed. If replication_confirmed is null, this field is also null.||
+|trash_at|datetime|If @trash_at@ is non-null and in the past, this collection will be hidden from API calls. May be untrashed.||
+|delete_at|datetime|If @delete_at@ is non-null and in the past, the collection may be permanently deleted.||
+|is_trashed|datetime|True if @trash_at@ is in the past, false if not.||
h3. Conditions of creating a Collection
h3. delete
-Delete an existing Collection.
+Put a Collection in the trash. This sets the @trash_at@ field to @now@ and @delete_at@ field to @now@ + token TTL. A trashed group is invisible to most API calls unless the @include_trash@ parameter is true.
Arguments:
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Collection in question.|path||
|collection|object||query||
+
+h3. untrash
+
+Remove a Collection from the trash. This sets the @trash_at@ and @delete_at@ fields to @null@.
+
+Arguments:
+
+table(table table-bordered table-condensed).
+|_. Argument |_. Type |_. Description |_. Location |_. Example |
+{background:#ccffcc}.|uuid|string|The UUID of the Collection to untrash.|path||
+|ensure_unique_name|boolean (default false)|Rename collection uniquely if untrashing it would fail with a unique name conflict.|query||
null|
|description|text|||
|writable_by|array|List of UUID strings identifying Users and other Groups that have write permission for this Group. Only users who are allowed to administer the Group will receive a full list. Other users will receive a partial list that includes the Group's owner_uuid and (if applicable) their own user UUID.||
+|trash_at|datetime|If @trash_at@ is non-null and in the past, this group and all objects directly or indirectly owned by the group will be hidden from API calls. May be untrashed.||
+|delete_at|datetime|If @delete_at@ is non-null and in the past, the group and all objects directly or indirectly owned by the group may be permanently deleted.||
+|is_trashed|datetime|True if @trash_at@ is in the past, false if not.||
h2. Methods
h3. delete
-Delete an existing Group.
+Put a Group in the trash. This sets the @trash_at@ field to @now@ and @delete_at@ field to @now@ + token TTL. A trashed group is invisible to most API calls unless the @include_trash@ parameter is true. All objects directly or indirectly owned by the Group are considered trashed as well.
Arguments:
|_. Argument |_. Type |_. Description |_. Location |_. Example |
{background:#ccffcc}.|uuid|string|The UUID of the Group in question.|path||
|group|object||query||
+
+h3. untrash
+
+Remove a Group from the trash. This sets the @trash_at@ and @delete_at@ fields to @null@.
+
+Arguments:
+
+table(table table-bordered table-condensed).
+|_. Argument |_. Type |_. Description |_. Location |_. Example |
+{background:#ccffcc}.|uuid|string|The UUID of the Group to untrash.|path||
+|ensure_unique_name|boolean (default false)|Rename project uniquely if untrashing it would fail with a unique name conflict.|query||
class TrashableGroups < ActiveRecord::Migration
- def change
+ def up
add_column :groups, :trash_at, :datetime
- add_column :groups, :delete_at, :datetime
+ add_index(:groups, :trash_at)
+
add_column :groups, :is_trashed, :boolean, null: false, default: false
+ add_index(:groups, :is_trashed)
+
+ add_column :groups, :delete_at, :datetime
+ add_index(:groups, :delete_at)
+
+ Group.reset_column_information
+ add_index(:groups, [:owner_uuid, :name],
+ unique: true,
+ where: 'is_trashed = false',
+ name: 'index_groups_on_owner_uuid_and_name')
+ remove_index(:groups,
+ name: 'groups_owner_uuid_name_unique')
+ end
+
+ def down
+ Group.transaction do
+ add_index(:groups, [:owner_uuid, :name], unique: true,
+ name: 'groups_owner_uuid_name_unique')
+ remove_index(:groups,
+ name: 'index_groups_on_owner_uuid_and_name')
+
+ remove_index(:groups, :delete_at)
+ remove_column(:groups, :delete_at)
+
+ remove_index(:groups, :is_trashed)
+ remove_column(:groups, :is_trashed)
+
+ remove_index(:groups, :trash_at)
+ remove_column(:groups, :trash_at)
+ end
end
end
updated_at timestamp without time zone NOT NULL,
group_class character varying(255),
trash_at timestamp without time zone,
- delete_at timestamp without time zone,
- is_trashed boolean DEFAULT false NOT NULL
+ is_trashed boolean DEFAULT false NOT NULL,
+ delete_at timestamp without time zone
);
CREATE INDEX groups_full_text_search_idx ON groups USING gin (to_tsvector('english'::regconfig, (((((((((((((COALESCE(uuid, ''::character varying))::text || ' '::text) || (COALESCE(owner_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_client_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(modified_by_user_uuid, ''::character varying))::text) || ' '::text) || (COALESCE(name, ''::character varying))::text) || ' '::text) || (COALESCE(description, ''::character varying))::text) || ' '::text) || (COALESCE(group_class, ''::character varying))::text)));
---
--- Name: groups_owner_uuid_name_unique; Type: INDEX; Schema: public; Owner: -; Tablespace:
---
-
-CREATE UNIQUE INDEX groups_owner_uuid_name_unique ON groups USING btree (owner_uuid, name);
-
-
--
-- Name: groups_search_index; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE INDEX index_groups_on_created_at ON groups USING btree (created_at);
+--
+-- Name: index_groups_on_delete_at; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_groups_on_delete_at ON groups USING btree (delete_at);
+
+
--
-- Name: index_groups_on_group_class; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE INDEX index_groups_on_group_class ON groups USING btree (group_class);
+--
+-- Name: index_groups_on_is_trashed; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_groups_on_is_trashed ON groups USING btree (is_trashed);
+
+
--
-- Name: index_groups_on_modified_at; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE INDEX index_groups_on_owner_uuid ON groups USING btree (owner_uuid);
+--
+-- Name: index_groups_on_owner_uuid_and_name; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE UNIQUE INDEX index_groups_on_owner_uuid_and_name ON groups USING btree (owner_uuid, name) WHERE (is_trashed = false);
+
+
+--
+-- Name: index_groups_on_trash_at; Type: INDEX; Schema: public; Owner: -; Tablespace:
+--
+
+CREATE INDEX index_groups_on_trash_at ON groups USING btree (trash_at);
+
+
--
-- Name: index_groups_on_uuid; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
assert !Group.find_by_uuid(groups(:trashed_project).uuid).is_trashed
end
+ test "untrash project with name conflict #{auth}" do
+ authorize_with auth
+ [:trashed_project].each do |pr|
+ Group.find_by_uuid(groups(pr).uuid).update! is_trashed: false
+ end
+ gc = Group.create!({owner_uuid: "zzzzz-j7d0g-trashedproject1",
+ name: "trashed subproject 3",
+ group_class: "project"})
+ post :untrash, {
+ id: groups(:trashed_subproject3).uuid,
+ format: :json,
+ ensure_unique_name: true
+ }
+ assert_response :success
+ assert_match /^trashed subproject 3 \(\d{4}-\d\d-\d\d.*?Z\)$/, json_response['name']
+ end
end
end