1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-01 22:26:24 -07:00

Change naming convention from cyclical to cyclic, as the latter is more acurate

This commit is contained in:
Eggbertx 2025-01-19 11:58:18 -08:00
parent 3c33792284
commit 09c059edd2
17 changed files with 72 additions and 73 deletions

View file

@ -60,11 +60,10 @@ See [`frontend/README.md`](frontend/README.md) for information on working with S
## Roadmap
### Near future
* Fully implement cyclical threads
* Implement +50
* Add more banners
* Add more plugin support (more event triggers)
### Lower priority
* RSS feeds from boards/specific threads/specific usernames+tripcodes (such as newsanon)
* Pinning a post within a thread even if its not the OP, to prevent its deletion in a cyclical thread.
* Pinning a post within a thread even if its not the OP, to prevent its deletion in a cyclic thread.

View file

Before

Width:  |  Height:  |  Size: 753 B

After

Width:  |  Height:  |  Size: 753 B

Before After
Before After

View file

@ -7,11 +7,11 @@
viewBox="0 0 120 120"
version="1.1"
id="svg5"
inkscape:export-filename="cyclical.png"
inkscape:export-filename="cyclic.png"
inkscape:export-xdpi="12.8"
inkscape:export-ydpi="12.8"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
sodipodi:docname="cyclical.svg"
sodipodi:docname="cyclic.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

View file

@ -99,8 +99,8 @@ func (p *Post) Stickied() bool {
return p.thread.Stickied
}
func (p *Post) Cyclical() bool {
return p.thread.Cyclical
func (p *Post) Cyclic() bool {
return p.thread.Cyclic
}
// Select all from v_building_posts (and queries with the same columns) and call the callback function on each Post
@ -131,7 +131,7 @@ func QueryPosts(query string, params []any, cb func(*Post) error) error {
&post.LastModified, &post.ParentID, &lastBump, &post.Message, &post.MessageRaw, &post.BoardID,
&post.BoardDir, &post.OriginalFilename, &post.Filename, &post.Checksum, &post.Filesize,
&post.ThumbnailWidth, &post.ThumbnailHeight, &post.UploadWidth, &post.UploadHeight,
&post.thread.Locked, &post.thread.Stickied, &post.thread.Cyclical, &post.Country.Flag, &post.Country.Name,
&post.thread.Locked, &post.thread.Stickied, &post.thread.Cyclic, &post.Country.Flag, &post.Country.Name,
&post.IsDeleted)
if err = rows.Scan(dest...); err != nil {

View file

@ -322,7 +322,7 @@ type PostConfig struct {
StickyRepliesOnBoardPage int
NewThreadsRequireUpload bool
EnableCyclicThreads bool
CyclicalThreadNumPosts int
CyclicThreadNumPosts int
BanColors []string
BanMessage string

View file

@ -49,7 +49,7 @@ var (
RepliesOnBoardPage: 3,
StickyRepliesOnBoardPage: 1,
EnableCyclicThreads: true,
CyclicalThreadNumPosts: 500,
CyclicThreadNumPosts: 500,
BanMessage: "USER WAS BANNED FOR THIS POST",
EmbedWidth: 200,
EmbedHeight: 164,

View file

@ -415,7 +415,7 @@ func (board *Board) GetThreads(onlyNotDeleted bool, orderLastByBump bool, sticki
var thread Thread
err = rows.Scan(
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored,
&thread.Cyclical, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
&thread.Cyclic, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
)
if err != nil {
return threads, err

View file

@ -337,14 +337,14 @@ func (p *Post) UnlinkUploads(leaveDeletedBox bool) error {
return err
}
// InCyclicalThread returns true if the post is in a cyclical thread
func (p *Post) InCyclicalThread() (bool, error) {
var cyclical bool
err := QueryRowTimeoutSQL(nil, "SELECT cyclical FROM DBPREFIXthreads WHERE id = ?", []any{p.ThreadID}, []any{&cyclical})
// InCyclicThread returns true if the post is in a cyclic thread
func (p *Post) InCyclicThread() (bool, error) {
var cyclic bool
err := QueryRowTimeoutSQL(nil, "SELECT cyclical FROM DBPREFIXthreads WHERE id = ?", []any{p.ThreadID}, []any{&cyclic})
if errors.Is(err, sql.ErrNoRows) {
return false, ErrThreadDoesNotExist
}
return cyclical, err
return cyclic, err
}
// Delete sets the post as deleted and sets the deleted_at timestamp to the current time
@ -442,8 +442,8 @@ func (p *Post) Insert(bumpThread bool, boardID int, locked bool, stickied bool,
return tx.Commit()
}
// CyclicalThreadPost represents a post that should be deleted in a cyclical thread
type CyclicalThreadPost struct {
// CyclicThreadPost represents a post that should be deleted in a cyclic thread
type CyclicThreadPost struct {
PostID int // sql: post_id
ThreadID int // sql: thread_id
OPID int // sql: op_id
@ -452,8 +452,8 @@ type CyclicalThreadPost struct {
Dir string // sql: dir
}
// CyclicalPostsToBePruned returns posts that should be deleted in a cyclical thread that has reached its board's post limit
func (p *Post) CyclicalPostsToBePruned() ([]CyclicalThreadPost, error) {
// CyclicPostsToBePruned returns posts that should be deleted in a cyclic thread that has reached its board's post limit
func (p *Post) CyclicPostsToBePruned() ([]CyclicThreadPost, error) {
if p.IsTopPost {
// don't prune if this is the OP
return nil, nil
@ -461,8 +461,8 @@ func (p *Post) CyclicalPostsToBePruned() ([]CyclicalThreadPost, error) {
ctx, cancel := context.WithTimeout(context.Background(), gcdb.defaultTimeout)
defer cancel()
var cyclical bool
err := QueryRowContextSQL(ctx, nil, "SELECT cyclical FROM DBPREFIXthreads WHERE id = ?", []any{p.ThreadID}, []any{&cyclical})
var cyclic bool
err := QueryRowContextSQL(ctx, nil, "SELECT cyclical FROM DBPREFIXthreads WHERE id = ?", []any{p.ThreadID}, []any{&cyclic})
if errors.Is(err, sql.ErrNoRows) {
err = ErrThreadDoesNotExist
}
@ -470,7 +470,7 @@ func (p *Post) CyclicalPostsToBePruned() ([]CyclicalThreadPost, error) {
return nil, err
}
if !cyclical {
if !cyclic {
return nil, nil
}
@ -480,9 +480,9 @@ func (p *Post) CyclicalPostsToBePruned() ([]CyclicalThreadPost, error) {
return nil, err
}
defer rows.Close()
var posts []CyclicalThreadPost
var posts []CyclicThreadPost
for rows.Next() {
var post CyclicalThreadPost
var post CyclicThreadPost
if err = rows.Scan(&post.PostID, &post.ThreadID, &post.OPID, &post.Filename, &post.Dir); err != nil {
return nil, err
}
@ -495,17 +495,17 @@ func (p *Post) CyclicalPostsToBePruned() ([]CyclicalThreadPost, error) {
if !boardCfg.EnableCyclicThreads {
return nil, nil
}
cyclicalThreadMaxPosts := boardCfg.CyclicalThreadNumPosts
if cyclicalThreadMaxPosts < 1 {
cyclicThreadMaxPosts := boardCfg.CyclicThreadNumPosts
if cyclicThreadMaxPosts < 1 {
// no limit set
return nil, nil
}
if len(posts) == 0 || len(posts) < cyclicalThreadMaxPosts {
if len(posts) == 0 || len(posts) < cyclicThreadMaxPosts {
return nil, nil
}
return posts[:len(posts)-cyclicalThreadMaxPosts], nil
return posts[:len(posts)-cyclicThreadMaxPosts], nil
}
func (p *Post) WebPath() string {

View file

@ -272,7 +272,7 @@ type Thread struct {
Locked bool // sql: locked
Stickied bool // sql: stickied
Anchored bool // sql: anchored
Cyclical bool // sql: cyclical
Cyclic bool // sql: cyclical
LastBump time.Time // sql: last_bump
DeletedAt time.Time // sql: deleted_at
IsDeleted bool // sql: is_deleted

View file

@ -21,7 +21,7 @@ var (
)
// CreateThread creates a new thread in the database with the given board ID and statuses
func CreateThread(tx *sql.Tx, boardID int, locked bool, stickied bool, anchored bool, cyclical bool) (threadID int, err error) {
func CreateThread(tx *sql.Tx, boardID int, locked bool, stickied bool, anchored bool, cyclic bool) (threadID int, err error) {
const lockedQuery = `SELECT locked FROM DBPREFIXboards WHERE id = ?`
const insertQuery = `INSERT INTO DBPREFIXthreads (board_id, locked, stickied, anchored, cyclical) VALUES (?,?,?,?,?)`
var boardIsLocked bool
@ -31,7 +31,7 @@ func CreateThread(tx *sql.Tx, boardID int, locked bool, stickied bool, anchored
if boardIsLocked {
return 0, ErrBoardIsLocked
}
if _, err = ExecTxSQL(tx, insertQuery, boardID, locked, stickied, anchored, cyclical); err != nil {
if _, err = ExecTxSQL(tx, insertQuery, boardID, locked, stickied, anchored, cyclic); err != nil {
return 0, err
}
return threadID, QueryRowTxSQL(tx, "SELECT MAX(id) FROM DBPREFIXthreads", nil, []any{&threadID})
@ -42,7 +42,7 @@ func GetThread(threadID int) (*Thread, error) {
const query = selectThreadsBaseSQL + `WHERE id = ?`
thread := new(Thread)
err := QueryRowSQL(query, []any{threadID}, []any{
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclical,
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclic,
&thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
})
return thread, err
@ -53,7 +53,7 @@ func GetPostThread(opID int) (*Thread, error) {
const query = selectThreadsBaseSQL + `WHERE id = (SELECT thread_id FROM DBPREFIXposts WHERE id = ? LIMIT 1)`
thread := new(Thread)
err := QueryRowSQL(query, []any{opID}, []any{
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclical,
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored, &thread.Cyclic,
&thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
})
if errors.Is(err, sql.ErrNoRows) {
@ -91,7 +91,7 @@ func GetThreadsWithBoardID(boardID int, onlyNotDeleted bool) ([]Thread, error) {
var thread Thread
if err = rows.Scan(
&thread.ID, &thread.BoardID, &thread.Locked, &thread.Stickied, &thread.Anchored,
&thread.Cyclical, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
&thread.Cyclic, &thread.LastBump, &thread.DeletedAt, &thread.IsDeleted,
); err != nil {
return threads, err
}
@ -207,7 +207,7 @@ func (t *Thread) GetUploads() ([]Upload, error) {
}
// UpdateAttribute updates the given attribute (valid attribute values are "locked", "stickied, "anchored",
// or "cyclical") for the thread
// or "cyclic") for the thread
func (t *Thread) UpdateAttribute(attribute string, value bool) error {
updateSQL := "UPDATE DBPREFIXthreads SET "
switch attribute {
@ -217,8 +217,8 @@ func (t *Thread) UpdateAttribute(attribute string, value bool) error {
t.Stickied = value
case "anchored":
t.Anchored = value
case "cyclical":
t.Cyclical = value
case "cyclic":
t.Cyclic = value
default:
return fmt.Errorf("invalid thread attribute %q", attribute)
}

View file

@ -534,14 +534,14 @@ func threadAttrsCallback(_ http.ResponseWriter, request *http.Request, _ *gcsql.
attr = "anchored"
newVal = true
doChange = thread.Anchored != newVal
} else if request.FormValue("uncyclical") != "" {
attr = "cyclical"
} else if request.FormValue("uncyclic") != "" {
attr = "cyclic"
newVal = false
doChange = thread.Cyclical != newVal
} else if request.FormValue("cyclical") != "" {
attr = "cyclical"
doChange = thread.Cyclic != newVal
} else if request.FormValue("cyclic") != "" {
attr = "cyclic"
newVal = true
doChange = thread.Cyclical != newVal
doChange = thread.Cyclic != newVal
}
if attr != "" && doChange {

View file

@ -333,10 +333,10 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
}
}
isCyclical := request.PostFormValue("cyclical") == "on"
if isCyclical && boardConfig.CyclicalThreadNumPosts == 0 {
isCyclic := request.PostFormValue("cyclic") == "on"
if isCyclic && boardConfig.CyclicThreadNumPosts == 0 {
writer.WriteHeader(http.StatusBadRequest)
server.ServeError(writer, "Board does not support cyclical threads", wantsJSON, nil)
server.ServeError(writer, "Board does not support cyclic threads", wantsJSON, nil)
return
}
@ -431,7 +431,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
return
}
_, emailCommand := getEmailAndCommand(request)
if err = post.Insert(emailCommand != "sage", board.ID, isLocked, isSticky, false, isCyclical); err != nil {
if err = post.Insert(emailCommand != "sage", board.ID, isLocked, isSticky, false, isCyclic); err != nil {
errEv.Err(err).Caller().
Str("sql", "postInsertion").
Msg("Unable to insert post")
@ -488,15 +488,15 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
}
if !post.IsTopPost {
toBePruned, err := post.CyclicalPostsToBePruned()
toBePruned, err := post.CyclicPostsToBePruned()
if err != nil {
errEv.Err(err).Caller().Msg("Unable to get posts to be pruned from cyclical thread")
server.ServeError(writer, "Unable to get cyclical thread info", wantsJSON, nil)
errEv.Err(err).Caller().Msg("Unable to get posts to be pruned from cyclic thread")
server.ServeError(writer, "Unable to get cyclic thread info", wantsJSON, nil)
return
}
gcutil.LogInt("toBePruned", len(toBePruned), infoEv, errEv)
// prune posts from cyclical thread
// prune posts from cyclic thread
for _, prunePost := range toBePruned {
fmt.Printf("%#v\n", prunePost)
p := &gcsql.Post{ID: prunePost.PostID, ThreadID: prunePost.ThreadID}
@ -504,8 +504,8 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
if err = p.Delete(); err != nil {
errEv.Err(err).Caller().
Int("postID", prunePost.PostID).
Msg("Unable to prune post from cyclical thread")
server.ServeError(writer, "Unable to prune post from cyclical thread", wantsJSON, nil)
Msg("Unable to prune post from cyclic thread")
server.ServeError(writer, "Unable to prune post from cyclic thread", wantsJSON, nil)
return
}
if prunePost.Filename != "" && prunePost.Filename != "deleted" {

View file

@ -48,8 +48,8 @@
<td><input type="submit" name="{{if $.thread.Anchored}}unanchor{{else}}anchor{{end}}" value="{{if $.thread.Anchored}}Anchored{{else}}Not anchored{{end}}" /></td>
</tr>
<tr>
<th>Cyclical</th>
<td><input type="submit" name="{{if $.thread.Cyclical}}uncyclical{{else}}cyclical{{end}}" value="{{if $.thread.Cyclical}}Cyclical{{else}}Not cyclical{{end}}" /></td>
<th>Cyclic</th>
<td><input type="submit" name="{{if $.thread.Cyclic}}uncyclic{{else}}cyclic{{end}}" value="{{if $.thread.Cyclic}}Cyclic{{else}}Not cyclic{{end}}" /></td>
</tr>
</table>
</form>

View file

@ -20,7 +20,7 @@
<span class="status-icons">
{{- if $.thread.Locked}}<img src="{{webPath `/static/lock.png`}}" class="locked-icon" alt="Thread locked" title="Thread locked">{{end -}}
{{- if $.thread.Stickied}}<img src="{{webPath `/static/sticky.png`}}" class="sticky-icon" alt="Sticky" title="Sticky">{{end -}}
{{- if $.thread.Cyclical}}<img src="{{webPath `/static/cyclical.png`}}" class="cyclical-icon" alt="Cyclical thread" title="Cyclical thread">{{end -}}
{{- if $.thread.Cyclic}}<img src="{{webPath `/static/cyclic.png`}}" class="cyclic-icon" alt="Cyclic thread" title="Cyclic thread">{{end -}}
</span>
{{if $.is_board_page -}}
[<a href="{{.post.ThreadPath}}">View</a>]

View file

@ -31,12 +31,12 @@
</tr>
{{- end -}}
{{with $.op}}{{else -}}
{{$noCyclicalThreads := or (eq $.boardConfig.CyclicalThreadNumPosts 0) (not $.boardConfig.EnableCyclicThreads)}}
<tr id="threadoptions" {{if $noCyclicalThreads}}style="display: none;"{{end}}>
{{$noCyclicThreads := or (eq $.boardConfig.CyclicThreadNumPosts 0) (not $.boardConfig.EnableCyclicThreads)}}
<tr id="threadoptions" {{if $noCyclicThreads}}style="display: none;"{{end}}>
<th class="postblock">Options</th>
<td>
{{if not $noCyclicalThreads}}
<label for="cyclical"><input type="checkbox" name="cyclical" id="cyclical"> Cyclical thread</label>
{{if not $noCyclicThreads}}
<label for="cyclic"><input type="checkbox" name="cyclic" id="cyclic"> Cyclic thread</label>
{{end}}
</td>
</tr>{{end}}

View file

@ -18,8 +18,8 @@ default_post_password = "12345"
default_board1 = "test"
default_board2 = "test2"
default_staff_board = "selenium"
default_cyclical_board = "cyclicaltest"
default_cyclical_count = 5
default_cyclic_board = "cyclictest"
default_cyclic_count = 5
default_admin_username = "selenium_admin"
default_admin_password = "password"
default_moderator_username = "selenium_moderator"
@ -37,8 +37,8 @@ class TestingOptions:
board1: str
board2: str
staff_board: str
cyclical_board: str
cyclical_count: int
cyclic_board: str
cyclic_count: int
name: str
email: str
subject: str
@ -69,8 +69,8 @@ class TestingOptions:
options.board1 = src_dict.get("board1", default_board1)
options.board2 = src_dict.get("board2", default_board2)
options.staff_board = src_dict.get("staff_board", default_staff_board)
options.cyclical_board = src_dict.get("cyclical_board", default_cyclical_board)
options.cyclical_count = src_dict.get("cyclical_count", default_cyclical_count)
options.cyclic_board = src_dict.get("cyclic_board", default_cyclic_board)
options.cyclic_count = src_dict.get("cyclic_count", default_cyclic_count)
options.name = src_dict.get("name", default_name)
options.email = src_dict.get("email", default_email)
options.subject = src_dict.get("subject", default_subject)

View file

@ -94,23 +94,23 @@ class TestPosting(SeleniumTestCase):
WebDriverWait(self.driver, 10).until(EC.url_changes(cur_url))
self.assertNotIn("Error :c", self.driver.title, "No errors when we try to delete the moved thread")
def test_cyclical(self):
self.assertTrue(self.options.board_exists(self.options.cyclical_board), f"Confirming that /{self.options.cyclical_board}/ exists")
def test_cyclic(self):
self.assertTrue(self.options.board_exists(self.options.cyclic_board), f"Confirming that /{self.options.cyclic_board}/ exists")
self.options.goto_page(self.options.cyclical_board)
self.options.goto_page(self.options.cyclic_board)
WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "form#postform input[type=submit]")))
form = self.driver.find_element(by=By.CSS_SELECTOR, value="form#postform")
send_post(form,
self.options.name,
"noko",
"Cyclical thread test",
"Cyclical thread OP",
"Cyclic thread test",
"Cyclic thread OP",
path.abspath(self.options.upload_path),
self.options.post_password)
WebDriverWait(self.driver, 10).until(EC.url_matches(threadRE))
for r in range(self.options.cyclical_count + 2):
for r in range(self.options.cyclic_count + 2):
form = self.driver.find_element(by=By.CSS_SELECTOR, value="form#postform")
send_post(form,
self.options.name,
@ -125,6 +125,6 @@ class TestPosting(SeleniumTestCase):
cur_url = self.driver.current_url
threadID = threadRE.findall(cur_url)[0][1]
replies = self.driver.find_elements(by=By.CSS_SELECTOR, value="div.reply")
self.assertEqual(len(replies), self.options.cyclical_count, "Verify that the cyclical thread has the correct number of replies")
self.assertEqual(len(replies), self.options.cyclic_count, "Verify that the cyclic thread has the correct number of replies")
self.assertEqual(replies[0].find_element(by=By.CSS_SELECTOR, value="div.post-text").text, "3", "Verify that the first reply is the third post")
delete_post(self.options, int(threadID), self.options.post_password)