-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #269 from tingyuchang/delete_article
[WIP] Delete article
- Loading branch information
Showing
11 changed files
with
493 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package api | ||
|
||
import ( | ||
"github.com/Ptt-official-app/go-pttbbs/bbs" | ||
"github.com/Ptt-official-app/go-pttbbs/ptttype" | ||
"github.com/gin-gonic/gin" | ||
) | ||
|
||
const DELETE_ARTICLES_R = "/board/:bid/deletearticles" | ||
|
||
type DeleteArticlesParams struct { | ||
ArticleIDs []bbs.ArticleID `json:"aids" form:"aids" url:"aids" binding:"required"` | ||
} | ||
|
||
type DeleteArticlesPath struct { | ||
BBoardID bbs.BBoardID `uri:"bid" binding:"required"` | ||
} | ||
|
||
type DeleteArticlesResult struct { | ||
Indexes []ptttype.SortIdx `json:"indexes"` | ||
} | ||
|
||
func DeleteArticlesWrapper(c *gin.Context) { | ||
params := &DeleteArticlesParams{} | ||
path := &DeleteArticlesPath{} | ||
LoginRequiredPathJSON(DeleteArticles, params, path, c) | ||
} | ||
|
||
func DeleteArticles(remoteAddr string, uuserID bbs.UUserID, params interface{}, path interface{}) (result interface{}, err error) { | ||
theParams, ok := params.(*DeleteArticlesParams) | ||
if !ok { | ||
return nil, ErrInvalidParams | ||
} | ||
|
||
thePath, ok := path.(*DeleteArticlesPath) | ||
if !ok { | ||
return nil, ErrInvalidPath | ||
} | ||
|
||
result, err = bbs.DeleteArticles(uuserID, thePath.BBoardID, theParams.ArticleIDs, remoteAddr) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return DeleteArticlesResult{Indexes: result.([]ptttype.SortIdx)}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package api | ||
|
||
import ( | ||
"encoding/binary" | ||
"os" | ||
"reflect" | ||
"sync" | ||
"testing" | ||
|
||
"github.com/Ptt-official-app/go-pttbbs/bbs" | ||
"github.com/Ptt-official-app/go-pttbbs/types" | ||
|
||
"github.com/Ptt-official-app/go-pttbbs/ptttype" | ||
) | ||
|
||
func TestDeleteArticles(t *testing.T) { | ||
setupTest(t.Name()) | ||
defer teardownTest(t.Name()) | ||
boardID0 := &ptttype.BoardID_t{} | ||
copy(boardID0[:], []byte("10_WhoAmI")) | ||
|
||
filename0 := &ptttype.Filename_t{} | ||
copy(filename0[:], []byte("M.1607202239.A.30D")) | ||
|
||
filename1 := &ptttype.Filename_t{} | ||
copy(filename1[:], []byte("M.1607203395.A.00D")) | ||
|
||
fileHeaderRaw1 := &ptttype.FileHeaderRaw{ | ||
Filename: ptttype.Filename_t{ // M.1607202239.A.30D | ||
0x4d, 0x2e, 0x31, 0x36, 0x30, 0x37, 0x32, 0x30, | ||
0x32, 0x32, 0x33, 0x39, 0x2e, 0x41, 0x2e, 0x33, | ||
0x30, 0x44, | ||
}, | ||
Modified: 1607202238, | ||
Owner: ptttype.Owner_t{0x53, 0x59, 0x53, 0x4f, 0x50}, // SYSOP | ||
Date: ptttype.Date_t{0x31, 0x32, 0x2f, 0x30, 0x36}, // 12/06 | ||
Title: ptttype.Title_t{ //[問題] 我是誰?~ | ||
0x5b, 0xb0, 0xdd, 0xc3, 0x44, 0x5d, 0x20, 0xa7, | ||
0xda, 0xac, 0x4f, 0xbd, 0xd6, 0xa1, 0x48, 0xa1, | ||
0xe3, | ||
}, | ||
} | ||
fileHeaderRaw2 := &ptttype.FileHeaderRaw{ | ||
Filename: ptttype.Filename_t{ // M.1607203395.A.00D | ||
0x4d, 0x2e, 0x31, 0x36, 0x30, 0x37, 0x32, 0x30, | ||
0x33, 0x33, 0x39, 0x35, 0x2e, 0x41, 0x2e, 0x30, | ||
0x30, 0x44, | ||
}, | ||
Modified: 1607203394, | ||
Owner: ptttype.Owner_t{0x53, 0x59, 0x53, 0x4f, 0x50}, // SYSOP | ||
Date: ptttype.Date_t{0x31, 0x32, 0x2f, 0x30, 0x36}, // 12/06 | ||
Title: ptttype.Title_t{ //[心得] 然後呢?~ | ||
0x5b, 0xa4, 0xdf, 0xb1, 0x6f, 0x5d, 0x20, 0xb5, | ||
0x4d, 0xab, 0xe1, 0xa9, 0x4f, 0xa1, 0x48, 0xa1, | ||
0xe3, | ||
}, | ||
Filemode: ptttype.FILE_MULTI, | ||
} | ||
case_1_FileHeaders := []ptttype.FileHeaderRaw{ | ||
*fileHeaderRaw1, // M.1607202239.A.30D | ||
*fileHeaderRaw2, // M.1607203395.A.00D | ||
} | ||
case_1_Filename := "./testcase/boards/W/WhoAmI/.DIR" | ||
defer os.RemoveAll(case_1_Filename) | ||
file, _ := os.OpenFile(case_1_Filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) | ||
defer file.Close() | ||
_ = types.BinaryWrite(file, binary.LittleEndian, case_1_FileHeaders) | ||
|
||
params0 := &DeleteArticlesParams{ | ||
ArticleIDs: []bbs.ArticleID{bbs.ToArticleID(filename0)}, | ||
} | ||
|
||
path0 := &DeleteArticlesPath{ | ||
BBoardID: "10_WhoAmI", | ||
} | ||
|
||
type args struct { | ||
remoteAddr string | ||
uuserID bbs.UUserID | ||
params interface{} | ||
path interface{} | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
wantResult interface{} | ||
wantErr bool | ||
}{ | ||
// TODO: Add test cases. | ||
{ | ||
"", | ||
args{ | ||
"127.0.0.1", | ||
"SYSOP", | ||
params0, | ||
path0, | ||
}, | ||
DeleteArticlesResult{Indexes: []ptttype.SortIdx{1}}, | ||
false, | ||
}, | ||
} | ||
var wg sync.WaitGroup | ||
for _, tt := range tests { | ||
wg.Add(1) | ||
t.Run(tt.name, func(t *testing.T) { | ||
wg.Done() | ||
gotResult, err := DeleteArticles(tt.args.remoteAddr, tt.args.uuserID, tt.args.params, tt.args.path) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("DeleteArticles() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if !reflect.DeepEqual(gotResult, tt.wantResult) { | ||
t.Errorf("DeleteArticles() gotResult = %v, want %v", gotResult, tt.wantResult) | ||
} | ||
}) | ||
wg.Wait() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package bbs | ||
|
||
import ( | ||
"github.com/Ptt-official-app/go-pttbbs/ptt" | ||
"github.com/Ptt-official-app/go-pttbbs/ptttype" | ||
) | ||
|
||
func DeleteArticles(uuserID UUserID, bboardID BBoardID, articleIDs []ArticleID, ip string) ([]ptttype.SortIdx, error) { | ||
userIDRaw, err := uuserID.ToRaw() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
uid, userecRaw, err := ptt.InitCurrentUser(userIDRaw) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
bid, boardIDRaw, err := bboardID.ToRaw() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var result []ptttype.SortIdx | ||
for _, articleID := range articleIDs { | ||
filename := articleID.ToFilename() | ||
createTime, err := filename.CreateTime() | ||
if err != nil { | ||
return nil, err | ||
} | ||
startIdx, err := ptt.FindArticleStartIdx(userecRaw, uid, boardIDRaw, bid, createTime, filename, false) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// FindArticleStartIdx only find nearest idx, so we must make sure filename is exactly correct | ||
summariesRaw, _, _, _, _ := ptt.LoadGeneralArticles(userecRaw, uid, boardIDRaw, bid, startIdx, 1, true) | ||
if len(summariesRaw) == 1 { | ||
articleSummary := NewArticleSummaryFromRaw(bboardID, summariesRaw[0]) | ||
if articleID == articleSummary.ArticleID { | ||
err = ptt.DeleteArticles(boardIDRaw, filename, startIdx) | ||
// TODO is need recover deleted items if get error? | ||
if err != nil { | ||
return nil, err | ||
} | ||
result = append(result, startIdx) | ||
} | ||
} | ||
} | ||
return result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
package bbs | ||
|
||
import ( | ||
"encoding/binary" | ||
"os" | ||
"sync" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/Ptt-official-app/go-pttbbs/ptttype" | ||
"github.com/Ptt-official-app/go-pttbbs/types" | ||
) | ||
|
||
func TestDeleteArticles(t *testing.T) { | ||
setupTest() // SetBBSHOME("./testcase") | ||
defer teardownTest() | ||
|
||
boardID0 := &ptttype.BoardID_t{} | ||
copy(boardID0[:], []byte("10_WhoAmI")) | ||
|
||
filename0 := &ptttype.Filename_t{} | ||
copy(filename0[:], []byte("M.1607202239.A.30D")) | ||
|
||
filename1 := &ptttype.Filename_t{} | ||
copy(filename1[:], []byte("M.1607203395.A.00D")) | ||
|
||
fileHeaderRaw1 := &ptttype.FileHeaderRaw{ | ||
Filename: ptttype.Filename_t{ // M.1607202239.A.30D | ||
0x4d, 0x2e, 0x31, 0x36, 0x30, 0x37, 0x32, 0x30, | ||
0x32, 0x32, 0x33, 0x39, 0x2e, 0x41, 0x2e, 0x33, | ||
0x30, 0x44, | ||
}, | ||
Modified: 1607202238, | ||
Owner: ptttype.Owner_t{0x53, 0x59, 0x53, 0x4f, 0x50}, // SYSOP | ||
Date: ptttype.Date_t{0x31, 0x32, 0x2f, 0x30, 0x36}, // 12/06 | ||
Title: ptttype.Title_t{ //[問題] 我是誰?~ | ||
0x5b, 0xb0, 0xdd, 0xc3, 0x44, 0x5d, 0x20, 0xa7, | ||
0xda, 0xac, 0x4f, 0xbd, 0xd6, 0xa1, 0x48, 0xa1, | ||
0xe3, | ||
}, | ||
} | ||
fileHeaderRaw2 := &ptttype.FileHeaderRaw{ | ||
Filename: ptttype.Filename_t{ // M.1607203395.A.00D | ||
0x4d, 0x2e, 0x31, 0x36, 0x30, 0x37, 0x32, 0x30, | ||
0x33, 0x33, 0x39, 0x35, 0x2e, 0x41, 0x2e, 0x30, | ||
0x30, 0x44, | ||
}, | ||
Modified: 1607203394, | ||
Owner: ptttype.Owner_t{0x53, 0x59, 0x53, 0x4f, 0x50}, // SYSOP | ||
Date: ptttype.Date_t{0x31, 0x32, 0x2f, 0x30, 0x36}, // 12/06 | ||
Title: ptttype.Title_t{ //[心得] 然後呢?~ | ||
0x5b, 0xa4, 0xdf, 0xb1, 0x6f, 0x5d, 0x20, 0xb5, | ||
0x4d, 0xab, 0xe1, 0xa9, 0x4f, 0xa1, 0x48, 0xa1, | ||
0xe3, | ||
}, | ||
Filemode: ptttype.FILE_MULTI, | ||
} | ||
case_1_FileHeaders := []ptttype.FileHeaderRaw{ | ||
*fileHeaderRaw1, // M.1607202239.A.30D | ||
*fileHeaderRaw2, // M.1607203395.A.00D | ||
} | ||
case_1_Filename := "./testcase/boards/W/WhoAmI/.DIR" | ||
defer os.RemoveAll(case_1_Filename) | ||
file, _ := os.OpenFile(case_1_Filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o644) | ||
defer file.Close() | ||
_ = types.BinaryWrite(file, binary.LittleEndian, case_1_FileHeaders) | ||
|
||
type args struct { | ||
uuserID UUserID | ||
bboardID BBoardID | ||
articleIDs []ArticleID | ||
ip string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
results []ptttype.SortIdx | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "test DeleteArticles w/o error", | ||
args: args{ | ||
uuserID: "SYSOP", | ||
bboardID: "10_WhoAmI", | ||
articleIDs: []ArticleID{ToArticleID(filename0)}, | ||
ip: "127.0.0.1", | ||
}, | ||
results: []ptttype.SortIdx{1}, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "test DeleteArticles Delete index 2 article", | ||
args: args{ | ||
uuserID: "SYSOP", | ||
bboardID: "10_WhoAmI", | ||
articleIDs: []ArticleID{ToArticleID(filename1)}, | ||
ip: "127.0.0.1", | ||
}, | ||
results: []ptttype.SortIdx{2}, | ||
wantErr: false, | ||
}, | ||
} | ||
var wg sync.WaitGroup | ||
for _, tt := range tests { | ||
wg.Add(1) | ||
t.Run(tt.name, func(t *testing.T) { | ||
wg.Done() | ||
idx, err := DeleteArticles(tt.args.uuserID, tt.args.bboardID, tt.args.articleIDs, tt.args.ip) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("DeleteArticles() error = %v, wantErr %v", err, tt.wantErr) | ||
} | ||
|
||
if !assert.ElementsMatch(t, idx, tt.results) { | ||
t.Errorf("DeleteArticles() result = %v, wanted %v", idx, tt.results) | ||
} | ||
}) | ||
wg.Wait() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.