proto: added subreddits proto

This commit is contained in:
Tigor Hutasuhut 2024-08-09 15:22:54 +07:00
parent 3ae3606ca1
commit 114a6d5116
9 changed files with 233 additions and 3 deletions

View file

@ -5,8 +5,8 @@ CREATE TABLE subreddits (
disable_scheduler TINYINT NOT NULL DEFAULT 0,
"type" VARCHAR(5) NOT NULL DEFAULT 'r',
schedule VARCHAR(20) NOT NULL DEFAULT '@daily',
countback INT NOT NULL DEFAULT 300,
image_cover VARCHAR(255) NOT NULL DEFAULT '',
countback BIGINT NOT NULL DEFAULT 300,
cover_image_id INTEGER,
created_at BIGINT DEFAULT (strftime('%s', 'now')) NOT NULL,
updated_at BIGINT DEFAULT (strftime('%s', 'now')) NOT NULL
);

View file

@ -27,7 +27,10 @@ CREATE TABLE images(
CONSTRAINT fk_image_devices_slug
FOREIGN KEY (device)
REFERENCES devices(slug)
ON DELETE CASCADE
ON DELETE CASCADE,
CONSTRAINT fk_image_subreddit_cover
FOREIGN KEY (id)
REFERENCES subreddits(cover_image_id)
);
CREATE INDEX idx_subreddit_images_blacklisted ON images(subreddit, blacklisted);
@ -36,6 +39,21 @@ CREATE INDEX idx_images_nsfw_blacklisted ON images(nsfw, blacklisted);
CREATE INDEX idx_images_created_at_nsfw_blacklisted ON images(created_at DESC, nsfw, blacklisted);
CREATE INDEX idx_images_blacklisted ON images(blacklisted);
CREATE UNIQUE INDEX idx_unique_images_per_device ON images(device, post_name);
CREATE TRIGGER images_update_timestamp AFTER UPDATE ON images FOR EACH ROW
BEGIN
UPDATE images SET updated_at = strftime('%s', 'now') WHERE id = old.id;
END;
CREATE TRIGGER images_update_subreddit_cover_on_insert AFTER INSERT ON images FOR EACH ROW
BEGIN
UPDATE subreddits SET cover_image_id = new.id WHERE name = new.subreddit AND cover_image_id IS NULL;
END;
CREATE TRIGGER images_update_subreddit_cover_on_delete AFTER DELETE ON images FOR EACH ROW
BEGIN
UPDATE subreddits SET cover_image_id = NULL WHERE cover_image_id = old.id;
END;
-- +goose StatementEnd
-- +goose Down

View file

@ -0,0 +1,32 @@
syntax = "proto3";
package subreddits.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1";
message CreateSubredditRequest {
// name of the subreddits to insert.
//
// accept insensitive casing, but casing
// will change to what Reddit has for
// consistency.
string name = 1 [(buf.validate.field).string.min_len = 1];
bool disable_scheduler = 2;
SubredditType type = 3;
// schedule is cron job spec to set schedule on when
// the runner for this subreddit runs.
string schedule = 4 [(buf.validate.field).string.min_len = 1];
uint32 countback = 5 [(buf.validate.field).uint32.gt = 0];
}
enum SubredditType {
SUBREDDIT_TYPE_UNSPECIFIED = 0;
SUBREDDIT_TYPE_SUBREDDIT = 1;
SUBREDDIT_TYPE_USER = 2;
}
message CreateSubredditResponse {
string name = 1;
}

View file

@ -0,0 +1,25 @@
syntax = "proto3";
package subreddits.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1";
message DeleteSubredditRequest {
// name of the subreddit to delete
string name = 1 [(buf.validate.field).string.min_len = 1];
// if true, delete all images associated with the subreddit
// from disk as well.
bool delete_images = 2;
}
message DeleteSubredditResponse {
// name of the subreddit that was deleted.
string name = 1;
// number of images that were deleted.
//
// always 0 if delete_images is false.
uint32 deleted_images = 2;
}

View file

@ -0,0 +1,42 @@
syntax = "proto3";
package subreddits.v1;
import "buf/validate/validate.proto";
import "subreddits/v1/create.proto";
option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1";
message GetSubredditRequest {
// name of the subreddit. Case insensitive.
//
// Returns error on not found.
string name = 1 [(buf.validate.field).string.min_len = 1];
}
message GetSubredditResponse {
string name = 1;
bool disable_scheduler = 2;
// type is never unspecified for this response.
//
// It's always either `SUBREDDIT_TYPE_SUBREDDIT`
// or `SUBREDDIT_TYPE_USER`.
SubredditType type = 3;
string schedule = 4;
uint32 countback = 5;
// cover_image_id is the id of an image that
// acts as the cover for this subreddit.
//
// May not be present in these kind of situations:
//
// - The background task runner has not run for this subreddit.
// - The image that is used as cover is deleted.
// - The subreddit does not contain any images.
//
// cover_image_id changes after every insert of
// new images in that subreddit, so avoid
// caching the image for too long.
optional uint32 cover_image_id = 6;
int64 created_at = 7;
int64 updated_at = 8;
}

View file

@ -0,0 +1,19 @@
syntax = "proto3";
package subreddits.v1;
import "buf/validate/validate.proto";
import "subreddits/v1/get.proto";
option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1";
message ListSubredditsRequest {
// name of the subreddit. Case insensitive.
//
// Returns error on not found.
string name = 1 [(buf.validate.field).string.min_len = 1];
}
message ListSubredditsResponse {
repeated GetSubredditResponse images = 1;
}

View file

@ -0,0 +1,17 @@
syntax = "proto3";
package subreddits.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1";
message ResolveSubredditNameRequest {
// name of the subreddit to resolve (check existence and casing).
string name = 1 [(buf.validate.field).string.min_len = 1];
}
message ResolveSubredditNameResponse {
// resolved the actual subreddit name.
string resolved = 1;
}

View file

@ -0,0 +1,53 @@
syntax = "proto3";
package subreddits.v1;
import "subreddits/v1/create.proto";
import "subreddits/v1/delete.proto";
import "subreddits/v1/get.proto";
import "subreddits/v1/list.proto";
import "subreddits/v1/resolve.proto";
import "subreddits/v1/update.proto";
option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1";
service SubredditsService {
// CreateSubreddit creates a new subreddit
//
// Returns the subreddit name.
//
// Returns the following error codes:
// - connect.CodeAlreadyExists if subreddit with the same name already exists.
// - connect.CodeInvalidArgument if validation failed, e.g. Invalid schedule cron format.
// - connect.CodeNotFound if the subreddit does not exist.
rpc CreateSubreddit(CreateSubredditRequest) returns (CreateSubredditResponse);
// GetSubreddit returns a subreddit by its name.
//
// Returns error with connect.CodeNotFound if subreddit does not exist.
rpc GetSubreddit(GetSubredditRequest) returns (GetSubredditResponse);
// ListSubreddits returns a list of subreddits.
rpc ListSubreddits(ListSubredditsRequest) returns (ListSubredditsResponse);
// UpdateSubreddit updates a subreddit.
//
// Only the fields that are set in the request will be updated.
//
// Returns error with connect.CodeNotFound if subreddit does not exist.
rpc UpdateSubreddit(UpdateSubredditRequest) returns (UpdateSubredditResponse);
// DeleteSubreddit deletes a subreddit.
//
// Returns error with connect.CodeNotFound if subreddit does not exist.
rpc DeleteSubreddit(DeleteSubredditRequest) returns (DeleteSubredditResponse);
// ResolveSubredditName resolves the given subreddit name.
//
// The returned resolved_name is the name that is actually
// used in Reddit.
//
// Returns error with connect.CodeNotFound if subreddit does not exist.
// So this rpc endpoint also acts to check subreddit's existence.
rpc ResolveSubredditName(ResolveSubredditNameRequest) returns (ResolveSubredditNameResponse);
}

View file

@ -0,0 +1,24 @@
syntax = "proto3";
package subreddits.v1;
import "buf/validate/validate.proto";
option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/subreddits/v1";
message UpdateSubredditRequest {
// The name of the subreddit to update.
string name = 1 [(buf.validate.field).string.min_len = 1];
SubredditSetter set = 2;
}
message SubredditSetter {
optional bool disable_scheduler = 1;
optional string schedule = 2 [(buf.validate.field).string.min_len = 1];
optional int64 countback = 3 [(buf.validate.field).int64.gt = 0];
}
message UpdateSubredditResponse {
// The updated subreddit.
string name = 1;
}