Skip to content

Commit

Permalink
add register router and fontend
Browse files Browse the repository at this point in the history
  • Loading branch information
TwinIsland committed Feb 10, 2025
1 parent 9dda94c commit a680607
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 6 deletions.
6 changes: 3 additions & 3 deletions include/crud.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Result get_info(const char *key, char **value);
Result push_info(const char *key, const char *value);

// Views
Result get_views();
Result get_views(Views *ret);

// Close database
void db_close(void);
// Visitors
Result add_visitor(Visitor *visitor, int *visitor_id_ret);
10 changes: 10 additions & 0 deletions include/models.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ typedef struct
int32_t UpVoted;
} Comment;

typedef struct
{
char *name;
char *email;
char *website;
int banned;
} Visitor;

void ViewsMap_Destroyer(void *cache);

void free_post(Post *post);
Expand All @@ -120,6 +128,7 @@ void free_views(Views *views);
void free_archieves(Archieves *archieves);
void free_PostInfos(PostInfos *post_infos);
void free_indexData(IndexData *indexData);
void free_visitor(Visitor *visitor);

char *notice_to_json(Notice *notice);
char *tags_to_json(Tags *tags);
Expand All @@ -129,3 +138,4 @@ char *postInfo_to_json(PostInfo *post_info);
char *archieves_to_json(Archieves *archieves);
char *postInfos_to_json(PostInfos *post_infos);
char *indexData_to_json(IndexData *index_data);
char *visitor_to_json(Visitor *visitor);
4 changes: 2 additions & 2 deletions include/router.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ void server_fn(struct mg_connection *c, int ev, void *ev_data);
// standard router reply int function, can be called by
// ROUTER_reply(c, router_name, int_response)
#define ROUTER_reply_int(c, router_name, int_response) \
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{ %m:%d, %m:%d }\n", \
MG_ESC("status"), 200, \
mg_http_reply(c, 200, "Content-Type: application/json\r\n", "{ %m:%m, %m:%d }\n", \
MG_ESC("status"), MG_ESC("true"), \
MG_ESC("content"), int_response);

#define ROUTER_reply_(c, router_name, content, content_type, code) \
Expand Down
6 changes: 6 additions & 0 deletions include/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ extern void exit_handler();
#define debug(msg, ...)
#endif

#define LOGGING(msg, ...) \
do \
{ \
printf("(LOGGING) " msg "\n", ##__VA_ARGS__); \
} while (0)

#define SHA256_PASS_MATCHED(pass1, pass2) strncmp((char *)pass1, (char *)pass2, SHA256_BLOCK_SIZE) == 0

// get the sha256 encrypt result from string, size equal to SHA256_BLOCK_SIZE
Expand Down
44 changes: 44 additions & 0 deletions src/crud.c
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,47 @@ Result get_PostInfos_from_n(int n, PostInfos *ret)

return (Result){.status = OK, .ptr = ret};
}

Result add_visitor(Visitor *visitor, int *visitor_id_ret)
{
if (db == NULL)
return UNINITIALIZE_ERR;

const char *sql = "INSERT INTO Visitors (Name, Email, Website) VALUES (?, ?, ?)";

sqlite3_stmt *stmt;

if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
return PREPARATION_ERR;

sqlite3_bind_text(stmt, 1, visitor->name, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, visitor->email, -1, SQLITE_STATIC);

if (visitor->website)
sqlite3_bind_text(stmt, 3, visitor->website, -1, SQLITE_STATIC);
else
sqlite3_bind_null(stmt, 3);

if (sqlite3_step(stmt) != SQLITE_DONE)
{
static char err_msg[256];
if (sqlite3_errcode(db) == 19) {
// unique constrain
snprintf(err_msg, sizeof(err_msg), "The username is already in use.");
}
else
snprintf(err_msg, sizeof(err_msg), "%s", sqlite3_errmsg(db));

sqlite3_finalize(stmt);
return (Result) {
.status = FAILED,
.msg = err_msg,
};
}

long long int visitor_id = sqlite3_last_insert_rowid(db);
*visitor_id_ret = visitor_id;
sqlite3_finalize(stmt);

return (Result){.status = OK};
}
18 changes: 18 additions & 0 deletions src/models.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ void free_indexData(IndexData *indexData)
free_archieves(&indexData->Archieves);
}

void free_visitor(Visitor *visitor)
{
free(visitor->email);
free(visitor->name);
free(visitor->website);
}

char *format_time(time_t t, char *timestamp_buf)
{
printf("Raw time_t value: %ld\n", t);
Expand Down Expand Up @@ -376,3 +383,14 @@ char *indexData_to_json(IndexData *index_data)

return json;
}

char *visitor_to_json(Visitor *visitor)
{
char *json = mg_mprintf("{%m: %m, %m: %m, %m: %m, %m: %d",
MG_ESC("name"), MG_ESC(visitor->name),
MG_ESC("email"), MG_ESC(visitor->email),
MG_ESC("website"), MG_ESC(visitor->website),
MG_ESC("banned"), MG_ESC(visitor->banned));

return json;
}
46 changes: 46 additions & 0 deletions src/router.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,49 @@ ROUTER(auth)
ROUTER_reply(c, "auth", UNAUTH_ERR);
}

ROUTER(visitor_register)
{
struct mg_str data = hm->body;

Visitor visitor = {0};
size_t ofs = 0;
struct mg_str key, val;

int field_n = 0;

while ((ofs = mg_json_next(data, ofs, &key, &val)) > 0)
{
if (mg_strcmp(key, mg_str("\"name\"")) == 0)
{
visitor.name = mg_str_without_paren(val);
field_n++;
}
else if (mg_strcmp(key, mg_str("\"email\"")) == 0)
{
visitor.email = mg_str_without_paren(val);
field_n++;
}
}

if (field_n == 2)
{
int ret_vid = -1;
Result ret = add_visitor(&visitor, &ret_vid);
if (ret.status == FAILED)
{
free_visitor(&visitor);
ROUTER_reply(c, "visitor_register", ret.msg, STRING_type, SERVERSIDE_ERR_CODE);
return;
}
LOGGING("user registor. name: %s\tid: %d", visitor.name, ret_vid);
ROUTER_reply_int(c, "visitor_register", ret_vid);
}
else
ROUTER_reply(c, "visitor_register", BADREQ_ERR);

free_visitor(&visitor);
}

// Connection event handler function
void server_fn(struct mg_connection *c, int ev, void *ev_data)
{
Expand Down Expand Up @@ -564,6 +607,9 @@ void server_fn(struct mg_connection *c, int ev, void *ev_data)
USE_ROUTER(views);
else if (mg_match(hm->uri, mg_str("/api/incLike#"), NULL))
USE_ROUTER(incLike);
else if (mg_match(hm->uri, mg_str("/api/visitor/register#"), NULL))
USE_ROUTER(visitor_register);

else
goto default_router;
}
Expand Down
118 changes: 117 additions & 1 deletion theme/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
<header class="flex three header">
<div class="none third-800" style="padding-bottom: 0;">
<span>Hi: </span>
<span style="font-style: italic;"><a href="#">Visitor</a></span>
<label style="font-style: italic; color: #B98A82;" for="login_modal"><u>Visitor</u></label>
</div>
<div style="text-align: center; padding-bottom: 0;" class="logo brand one-third third-800">
<a href="/" onclick="route()">
Expand Down Expand Up @@ -94,6 +94,64 @@ <h3>搜索 / Search</h3>
</article>
</div>

<!-- Login function modal -->
<div class="modal">
<input id="login_modal" type="checkbox" />
<label for="login_modal" class="overlay"></label>
<article style="width: 30rem;">
<header>
<h3>快捷登录</h3>
<label for="login_modal" class="close">&times;</label>
</header>
<section class="content" style="padding-top: 20px;">
<b>用户名:</b>
<input type="text" style="height: 45px;margin-bottom: 12px;margin-top: 5px;" placeholder="(*/ω\*)">
<b>电子邮箱:</b>
<input type="email" style="height: 45px;;margin-top: 5px" placeholder="(*/ω\*)">
</section>
<footer style="display: flex;align-items: center">
<label class="button" style="font-size: 1.2em;">登录</label>
<label for="register_modal" style="color: #B98A82;margin-left: 10px;"><u>注册账号</u></label>
<p style="color: rgba(33, 37, 41, 0.75); font-size: 2rem; user-select: none; margin-left: auto;">
ExpressAccount</p>
</footer>
</article>
</div>

<!-- Registor modal -->
<div class="modal">
<input id="register_modal" type="checkbox" />
<label for="register_modal" class="overlay"></label>
<article style="width: 30rem;">
<header>
<h3>注册账号</h3>
<label for="register_modal" class="close">&times;</label>
</header>
<section class="content" style="padding-top: 20px;">
<b>用户名:</b>
<p id="username_error" style="color: red; font-size: 0.9em; display: none;">用户名不能为空!</p>
<input id="username" type="text" style="height: 45px; margin-bottom: 12px; margin-top: 5px;"
placeholder="(*/ω\*)">

<b>电子邮箱:</b>
<p id="email_error" style="color: red; font-size: 0.9em; display: none;">请输入有效的电子邮件地址!</p>
<input id="email" type="email" style="height: 45px; margin-bottom: 12px; margin-top: 5px"
placeholder="(*/ω\*)">

<b>网站(可选):</b>
<input id="website" type="url" style="height: 45px; margin-top: 5px" placeholder="(*/ω\*)">
<p id="response_message" style="margin-left: auto; color: rgba(33, 37, 41, 0.75); font-size: 1rem;">
</p>
</section>
<footer style="display: flex; align-items: center">
<label class="button" style="font-size: 1.2em; cursor: pointer;"
onclick="registerAccount()">注册</label>
<label for="login_modal" style="color: #B98A82; margin-left: 10px;"><u>返回登陆</u></label>
</footer>
</article>
</div>


<hr style="color: rgb(248, 249, 250);">

<div class="navbar">
Expand Down Expand Up @@ -172,6 +230,64 @@ <h3>搜索 / Search</h3>
}
});
</script>

<script>
function registerAccount() {
const username = document.getElementById("username").value.trim();
const email = document.getElementById("email").value.trim();
const website = document.getElementById("website").value.trim();
const usernameError = document.getElementById("username_error");
const emailError = document.getElementById("email_error");
const responseMessage = document.getElementById("response_message");

// Reset error messages
usernameError.style.display = "none";
emailError.style.display = "none";
responseMessage.innerText = "";

// Validate input fields
let isValid = true;

if (username === "") {
usernameError.style.display = "block";
isValid = false;
}

if (email === "" || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
emailError.style.display = "block";
isValid = false;
}

if (!isValid) return;

let requestData = { name: username, email: email };
if (website !== "") {
requestData.website = website;
}

fetch("/api/visitor/register", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(requestData)
})
.then(response => response.json())
.then(data => {
if (data.status) {
responseMessage.style.color = "green";
responseMessage.innerText = `注册成功!你的ID: ${data.content}`;
} else {
responseMessage.style.color = "red";
responseMessage.innerText = `注册失败: ${data.content}`;
}
})
.catch(error => {
responseMessage.style.color = "red";
responseMessage.innerText = "服务器错误,请稍后再试。";
});
}
</script>
</body>

</html>

0 comments on commit a680607

Please sign in to comment.