feat: Enhance user permissions and update event handling with improved response structures
This commit is contained in:
@@ -65,6 +65,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
(
|
(
|
||||||
"3b9f8c4e-6a2d-4f8a-9a12-2d6f8b3c4e5a",
|
"3b9f8c4e-6a2d-4f8a-9a12-2d6f8b3c4e5a",
|
||||||
vec![
|
vec![
|
||||||
|
PermissionsEnum::ReadListUsers, // Added ReadListUsers permission
|
||||||
PermissionsEnum::ReadOwnMentorProfile,
|
PermissionsEnum::ReadOwnMentorProfile,
|
||||||
PermissionsEnum::UpdateOwnMentorProfile,
|
PermissionsEnum::UpdateOwnMentorProfile,
|
||||||
PermissionsEnum::ReadOwnMentorStatus,
|
PermissionsEnum::ReadOwnMentorStatus,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::{events_dto::EventsQueryDto, events_schema::EventsSchema};
|
use super::{events_dto::EventsQueryDto, events_schema::EventsSchema};
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use imphnen_libs::{AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDto};
|
use imphnen_libs::{AppState, MetaRequestDto, ResourceEnum, ResponseListSuccessDto};
|
||||||
use imphnen_utils::{DetailQueryBuilder, ListQueryBuilder, get_id, get_iso_date};
|
use imphnen_utils::{DetailQueryBuilder, ListQueryBuilder, get_id, get_iso_date, make_thing};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
@@ -46,8 +46,17 @@ impl<'a> EventsRepository<'a> {
|
|||||||
pub async fn query_event_by_id(&self, id: String) -> Result<EventsQueryDto> {
|
pub async fn query_event_by_id(&self, id: String) -> Result<EventsQueryDto> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let db = &self.state.surrealdb_ws;
|
let db = &self.state.surrealdb_ws;
|
||||||
|
// Attempt to parse the ID. If it's a full Thing (e.g., "events:some_id"), extract the ID part.
|
||||||
|
// Otherwise, assume it's already the raw ID.
|
||||||
|
let parsed_id = if id.contains(":") {
|
||||||
|
let thing = make_thing(ResourceEnum::Events.to_string().as_str(), &id);
|
||||||
|
get_id(&thing)?.1.to_string()
|
||||||
|
} else {
|
||||||
|
id.clone()
|
||||||
|
};
|
||||||
|
|
||||||
let builder = DetailQueryBuilder::new(ResourceEnum::Events.to_string())
|
let builder = DetailQueryBuilder::new(ResourceEnum::Events.to_string())
|
||||||
.with_id(&id)
|
.with_id(&parsed_id)
|
||||||
.with_select_fields(vec!["*"]);
|
.with_select_fields(vec!["*"]);
|
||||||
let sql = builder.build();
|
let sql = builder.build();
|
||||||
info!(query = %sql, "Executing SurrealDB query");
|
info!(query = %sql, "Executing SurrealDB query");
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ impl<'a> TestimonialsRepository<'a> {
|
|||||||
pub async fn query_create_testimonial(
|
pub async fn query_create_testimonial(
|
||||||
&self,
|
&self,
|
||||||
data: TestimonialsSchema,
|
data: TestimonialsSchema,
|
||||||
) -> Result<String> {
|
) -> Result<TestimonialsSchema> { // Change return type from String to TestimonialsSchema
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let db = &self.state.surrealdb_ws;
|
let db = &self.state.surrealdb_ws;
|
||||||
info!(
|
info!(
|
||||||
@@ -102,7 +102,7 @@ impl<'a> TestimonialsRepository<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match record {
|
match record {
|
||||||
Some(_) => Ok("Success create testimonial".into()),
|
Some(created_testimonial) => Ok(created_testimonial), // Return the created testimonial
|
||||||
None => bail!("Failed to create testimonial"),
|
None => bail!("Failed to create testimonial"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use imphnen_libs::{
|
|||||||
AppState, MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto,
|
AppState, MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto,
|
||||||
};
|
};
|
||||||
use imphnen_utils::{
|
use imphnen_utils::{
|
||||||
common_response, success_list_response, success_response, validate_request,
|
common_response, success_list_response, success_response, success_created_response, validate_request,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TestimonialsService;
|
pub struct TestimonialsService;
|
||||||
@@ -46,8 +46,8 @@ impl TestimonialsService {
|
|||||||
Ok(testimonial) if !testimonial.is_deleted => {
|
Ok(testimonial) if !testimonial.is_deleted => {
|
||||||
success_response(ResponseSuccessDto {
|
success_response(ResponseSuccessDto {
|
||||||
data: TestimonialsDetailItemDto {
|
data: TestimonialsDetailItemDto {
|
||||||
id: testimonial.id.id.to_raw(),
|
id: testimonial.id.to_raw(),
|
||||||
user_id: testimonial.user.id.id.to_raw(),
|
user_id: testimonial.user.id.to_raw(),
|
||||||
user_fullname: testimonial.user.fullname,
|
user_fullname: testimonial.user.fullname,
|
||||||
role: testimonial.role,
|
role: testimonial.role,
|
||||||
content: testimonial.content,
|
content: testimonial.content,
|
||||||
@@ -72,7 +72,19 @@ impl TestimonialsService {
|
|||||||
let repo = TestimonialsRepository::new(state);
|
let repo = TestimonialsRepository::new(state);
|
||||||
let schema = TestimonialsSchema::create(payload, &authenticated_user.id);
|
let schema = TestimonialsSchema::create(payload, &authenticated_user.id);
|
||||||
match repo.query_create_testimonial(schema).await {
|
match repo.query_create_testimonial(schema).await {
|
||||||
Ok(msg) => common_response(StatusCode::CREATED, &msg),
|
Ok(created_testimonial) => {
|
||||||
|
success_created_response(ResponseSuccessDto {
|
||||||
|
data: TestimonialsDetailItemDto {
|
||||||
|
id: created_testimonial.id.to_raw(),
|
||||||
|
user_id: created_testimonial.user.id.to_raw(),
|
||||||
|
user_fullname: authenticated_user.fullname.clone(),
|
||||||
|
role: created_testimonial.role,
|
||||||
|
content: created_testimonial.content,
|
||||||
|
created_at: created_testimonial.created_at,
|
||||||
|
updated_at: created_testimonial.updated_at,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
Err(e) => common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
Err(e) => common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -368,6 +368,7 @@ mod tests {
|
|||||||
let auth_request = AuthRequest {
|
let auth_request = AuthRequest {
|
||||||
code: "4/0-ARAA6EeEKN8rlQ_Dh5XAAA_dCpKFwKa3-Jl9cO7I".to_string(),
|
code: "4/0-ARAA6EeEKN8rlQ_Dh5XAAA_dCpKFwKa3-Jl9cO7I".to_string(),
|
||||||
state: "valid_state".to_string(),
|
state: "valid_state".to_string(),
|
||||||
|
redirect_uri: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = auth_request.validate();
|
let result = auth_request.validate();
|
||||||
@@ -379,6 +380,7 @@ mod tests {
|
|||||||
let auth_request = AuthRequest {
|
let auth_request = AuthRequest {
|
||||||
code: "authorization/code/with/slashes".to_string(),
|
code: "authorization/code/with/slashes".to_string(),
|
||||||
state: "valid_state".to_string(),
|
state: "valid_state".to_string(),
|
||||||
|
redirect_uri: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = auth_request.validate();
|
let result = auth_request.validate();
|
||||||
@@ -390,6 +392,7 @@ mod tests {
|
|||||||
let auth_request = AuthRequest {
|
let auth_request = AuthRequest {
|
||||||
code: "authorization+code+with+plus".to_string(),
|
code: "authorization+code+with+plus".to_string(),
|
||||||
state: "valid_state".to_string(),
|
state: "valid_state".to_string(),
|
||||||
|
redirect_uri: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = auth_request.validate();
|
let result = auth_request.validate();
|
||||||
@@ -401,6 +404,7 @@ mod tests {
|
|||||||
let auth_request = AuthRequest {
|
let auth_request = AuthRequest {
|
||||||
code: "authorization=code=with=equals=".to_string(),
|
code: "authorization=code=with=equals=".to_string(),
|
||||||
state: "valid_state".to_string(),
|
state: "valid_state".to_string(),
|
||||||
|
redirect_uri: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = auth_request.validate();
|
let result = auth_request.validate();
|
||||||
@@ -412,6 +416,7 @@ mod tests {
|
|||||||
let auth_request = AuthRequest {
|
let auth_request = AuthRequest {
|
||||||
code: "authorization@code#with$invalid%chars".to_string(),
|
code: "authorization@code#with$invalid%chars".to_string(),
|
||||||
state: "valid_state".to_string(),
|
state: "valid_state".to_string(),
|
||||||
|
redirect_uri: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = auth_request.validate();
|
let result = auth_request.validate();
|
||||||
@@ -423,6 +428,7 @@ mod tests {
|
|||||||
let auth_request = AuthRequest {
|
let auth_request = AuthRequest {
|
||||||
code: "".to_string(),
|
code: "".to_string(),
|
||||||
state: "valid_state".to_string(),
|
state: "valid_state".to_string(),
|
||||||
|
redirect_uri: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = auth_request.validate();
|
let result = auth_request.validate();
|
||||||
@@ -441,6 +447,7 @@ mod tests {
|
|||||||
let auth_request = AuthRequest {
|
let auth_request = AuthRequest {
|
||||||
code: "test_code".to_string(),
|
code: "test_code".to_string(),
|
||||||
state: token,
|
state: token,
|
||||||
|
redirect_uri: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate and extract PKCE verifier
|
// Validate and extract PKCE verifier
|
||||||
@@ -459,6 +466,7 @@ mod tests {
|
|||||||
let auth_request = AuthRequest {
|
let auth_request = AuthRequest {
|
||||||
code: "test_code".to_string(),
|
code: "test_code".to_string(),
|
||||||
state: token,
|
state: token,
|
||||||
|
redirect_uri: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Legacy validation should still work
|
// Legacy validation should still work
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use super::{
|
use super::{
|
||||||
UsersActiveInactiveRequestDto, UsersCreateRequestDto,
|
UsersActiveInactiveRequestDto, UsersCreateRequestDto,
|
||||||
UsersSetNewPasswordRequestDto, UsersUpdateRequestDto,
|
UsersSetNewPasswordRequestDto, UsersUpdateRequestDto,
|
||||||
|
users_dto::UsersDetailQueryDto, // Add this line
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
AppState, MetaRequestDto, ResponseListSuccessDto, UsersRepository, UsersSchema,
|
AppState, MetaRequestDto, ResponseListSuccessDto, UsersRepository, UsersSchema,
|
||||||
@@ -31,22 +32,27 @@ pub trait UsersServiceTrait: Send + Sync + 'static {
|
|||||||
async fn update_user_password(state: &AppState, email: String, payload: UsersSetNewPasswordRequestDto) -> Response;
|
async fn update_user_password(state: &AppState, email: String, payload: UsersSetNewPasswordRequestDto) -> Response;
|
||||||
async fn get_user_by_mentor_id(state: &AppState, mentor_id: String) -> Response;
|
async fn get_user_by_mentor_id(state: &AppState, mentor_id: String) -> Response;
|
||||||
async fn delete_user(state: &AppState, id: String) -> Response;
|
async fn delete_user(state: &AppState, id: String) -> Response;
|
||||||
|
async fn get_user_by_id_internal(&self, id: &surrealdb::sql::Thing, state: &AppState) -> Result<UsersDetailQueryDto>;
|
||||||
async fn get_user_by_email(&self, email: &str, state: &AppState) -> Result<Option<UserDto>>;
|
|
||||||
async fn create_user_by_dto(&self, new_user: CreateUserDto, state: &AppState) -> Result<UserDto>;
|
async fn get_user_by_email(&self, email: &str, state: &AppState) -> Result<Option<UserDto>>;
|
||||||
async fn update_user_avatar(&self, email: &str, avatar_url: Option<String>, state: &AppState) -> Result<()>;
|
async fn create_user_by_dto(&self, new_user: CreateUserDto, state: &AppState) -> Result<UserDto>;
|
||||||
async fn upload_file(state: &AppState, user_id: String, multipart: Multipart) -> Response;
|
async fn update_user_avatar(&self, email: &str, avatar_url: Option<String>, state: &AppState) -> Result<()>;
|
||||||
}
|
async fn upload_file(state: &AppState, user_id: String, multipart: Multipart) -> Response;
|
||||||
|
}
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct UsersService;
|
#[derive(Clone)]
|
||||||
|
pub struct UsersService;
|
||||||
impl UsersService {
|
|
||||||
}
|
impl UsersService {
|
||||||
|
}
|
||||||
#[async_trait]
|
|
||||||
impl UsersServiceTrait for UsersService {
|
#[async_trait]
|
||||||
async fn get_user_list(state: &AppState, meta: MetaRequestDto) -> Response {
|
impl UsersServiceTrait for UsersService {
|
||||||
|
async fn get_user_by_id_internal(&self, id: &surrealdb::sql::Thing, state: &AppState) -> Result<UsersDetailQueryDto> {
|
||||||
|
let repo = crate::UsersRepository::new(state);
|
||||||
|
repo.query_user_by_id(id).await
|
||||||
|
}
|
||||||
|
async fn get_user_list(state: &AppState, meta: MetaRequestDto) -> Response {
|
||||||
let repo = UsersRepository::new(state);
|
let repo = UsersRepository::new(state);
|
||||||
match repo.query_user_list(meta).await {
|
match repo.query_user_list(meta).await {
|
||||||
Ok(data) => {
|
Ok(data) => {
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ use imphnen_libs::{AppState, jsonwebtoken::decode_access_token};
|
|||||||
use imphnen_utils::common_response;
|
use imphnen_utils::common_response;
|
||||||
use axum_extra::headers::{authorization::Bearer, Authorization, HeaderMapExt};
|
use axum_extra::headers::{authorization::Bearer, Authorization, HeaderMapExt};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
|
use imphnen_iam::v1::users::{users_service::{UsersService, UsersServiceTrait}};
|
||||||
|
use imphnen_libs::ResourceEnum;
|
||||||
|
use imphnen_utils::make_thing;
|
||||||
|
|
||||||
pub async fn auth_middleware(
|
pub async fn auth_middleware(
|
||||||
Extension(_state): Extension<AppState>, // state is currently unused in this middleware
|
Extension(_state): Extension<AppState>, // state is currently unused in this middleware
|
||||||
@@ -32,6 +35,15 @@ pub async fn auth_middleware(
|
|||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
req.extensions_mut().insert(claims);
|
let user_id = claims.user_id.clone();
|
||||||
|
|
||||||
|
let repo = UsersService {};
|
||||||
|
let thing_id = make_thing(&ResourceEnum::Users.to_string(), &user_id);
|
||||||
|
let user_data = match repo.get_user_by_id_internal(&thing_id, &_state).await {
|
||||||
|
Ok(user) => user,
|
||||||
|
Err(_) => return Ok(common_response(StatusCode::UNAUTHORIZED, "User not found")),
|
||||||
|
};
|
||||||
|
|
||||||
|
req.extensions_mut().insert(user_data);
|
||||||
Ok(next.run(req).await)
|
Ok(next.run(req).await)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,3 +43,14 @@ pub fn common_response(status: StatusCode, message: &str) -> Response {
|
|||||||
)
|
)
|
||||||
.into_response()
|
.into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn success_created_response<T: Serialize>(params: ResponseSuccessDto<T>) -> Response {
|
||||||
|
(
|
||||||
|
StatusCode::CREATED,
|
||||||
|
Json(json!({
|
||||||
|
"data": params.data,
|
||||||
|
"version": "0.1.0",
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ SKIP_COMPREHENSIVE=false
|
|||||||
SKIP_CRUD=false
|
SKIP_CRUD=false
|
||||||
GENERATE_REPORT=false
|
GENERATE_REPORT=false
|
||||||
VERBOSE=false
|
VERBOSE=false
|
||||||
|
SKIP_CLEAR=false
|
||||||
|
SKIP_SEED=false
|
||||||
|
|
||||||
while getopts "sbcrgvh" opt; do
|
while getopts "sbcrgvhkd" opt; do
|
||||||
case ${opt} in
|
case ${opt} in
|
||||||
s ) START_SERVER=true ;;
|
s ) START_SERVER=true ;;
|
||||||
b ) SKIP_BASIC=true ;;
|
b ) SKIP_BASIC=true ;;
|
||||||
@@ -30,7 +32,7 @@ while getopts "sbcrgvh" opt; do
|
|||||||
r ) SKIP_CRUD=true ;;
|
r ) SKIP_CRUD=true ;;
|
||||||
g ) GENERATE_REPORT=true ;;
|
g ) GENERATE_REPORT=true ;;
|
||||||
v ) VERBOSE=true ;;
|
v ) VERBOSE=true ;;
|
||||||
h )
|
h )
|
||||||
echo "IMPHNEN API Test Suite"
|
echo "IMPHNEN API Test Suite"
|
||||||
echo "Usage: $0 [OPTIONS]"
|
echo "Usage: $0 [OPTIONS]"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -42,6 +44,8 @@ while getopts "sbcrgvh" opt; do
|
|||||||
echo " -g Generate JSON test report"
|
echo " -g Generate JSON test report"
|
||||||
echo " -v Verbose output (show all INFO logs)"
|
echo " -v Verbose output (show all INFO logs)"
|
||||||
echo " -h Show this help message"
|
echo " -h Show this help message"
|
||||||
|
echo " -d Skip database clear"
|
||||||
|
echo " -k Skip database seeding"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Examples:"
|
echo "Examples:"
|
||||||
echo " $0 # Run all tests"
|
echo " $0 # Run all tests"
|
||||||
@@ -49,11 +53,18 @@ while getopts "sbcrgvh" opt; do
|
|||||||
echo " $0 -g # Run tests and generate report"
|
echo " $0 -g # Run tests and generate report"
|
||||||
echo " $0 -sv # Start server with verbose output"
|
echo " $0 -sv # Start server with verbose output"
|
||||||
echo " $0 -bc # Run only public endpoint tests"
|
echo " $0 -bc # Run only public endpoint tests"
|
||||||
|
echo " $0 -d # Skip database clear"
|
||||||
|
echo " $0 -k # Skip database seeding"
|
||||||
|
echo " $0 -dk # Skip database clear and seeding"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
|
d ) SKIP_CLEAR=true ;;
|
||||||
|
k ) SKIP_SEED=true ;;
|
||||||
\? ) echo "Invalid option: -$OPTARG" >&2; echo "Use -h for help" >&2; exit 1 ;;
|
\? ) echo "Invalid option: -$OPTARG" >&2; echo "Use -h for help" >&2; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
# Shift past the options
|
||||||
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
if ! command -v curl &> /dev/null; then
|
if ! command -v curl &> /dev/null; then
|
||||||
echo "Error: 'curl' tidak ditemukan. Mohon install terlebih dahulu." >&2
|
echo "Error: 'curl' tidak ditemukan. Mohon install terlebih dahulu." >&2
|
||||||
@@ -72,6 +83,7 @@ FALED_TESTS_SUMMARY=()
|
|||||||
PASS_COUNT=0
|
PASS_COUNT=0
|
||||||
FAIL_COUNT=0
|
FAIL_COUNT=0
|
||||||
TEST_TESTIMONIAL_ID=""
|
TEST_TESTIMONIAL_ID=""
|
||||||
|
TEST_EVENT_ID=""
|
||||||
|
|
||||||
CYAN='\033[0;36m'
|
CYAN='\033[0;36m'
|
||||||
YELLOW='\033[0;33m'
|
YELLOW='\033[0;33m'
|
||||||
@@ -162,6 +174,10 @@ test_server_connection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear_database() {
|
clear_database() {
|
||||||
|
if [ "$SKIP_CLEAR" = true ]; then
|
||||||
|
write_test_log "INFO" "Melewatkan pembersihan database."
|
||||||
|
return
|
||||||
|
fi
|
||||||
write_test_log "INFO" "Membersihkan database via WebSocket..."
|
write_test_log "INFO" "Membersihkan database via WebSocket..."
|
||||||
if ! RUST_LOG=debug cargo run --bin clear_db_test --release; then
|
if ! RUST_LOG=debug cargo run --bin clear_db_test --release; then
|
||||||
write_test_log "ERROR" "Gagal membersihkan database."
|
write_test_log "ERROR" "Gagal membersihkan database."
|
||||||
@@ -433,7 +449,7 @@ test_comprehensive_with_user() {
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
"mentor@example.com")
|
"mentor@example.com")
|
||||||
test_api_endpoint "Get Users List - $fullname" "GET" "/v1/users" 403 "" true
|
test_api_endpoint "Get Users List - $fullname" "GET" "/v1/users" 200 "" true
|
||||||
test_api_endpoint "Get Roles List - $fullname" "GET" "/v1/roles" 403 "" true
|
test_api_endpoint "Get Roles List - $fullname" "GET" "/v1/roles" 403 "" true
|
||||||
test_api_endpoint "Get Permissions List - $fullname" "GET" "/v1/permissions" 403 "" true
|
test_api_endpoint "Get Permissions List - $fullname" "GET" "/v1/permissions" 403 "" true
|
||||||
test_api_endpoint "Get Mentors List - $fullname" "GET" "/v1/mentors" 200 "" true
|
test_api_endpoint "Get Mentors List - $fullname" "GET" "/v1/mentors" 200 "" true
|
||||||
@@ -448,7 +464,7 @@ test_comprehensive_with_user() {
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
"user@example.com")
|
"user@example.com")
|
||||||
test_api_endpoint "Get Users List - $fullname" "GET" "/v1/users" 403 "" true
|
test_api_endpoint "Get Users List - $fullname" "GET" "/v1/users" 200 "" true
|
||||||
test_api_endpoint "Get Roles List - $fullname" "GET" "/v1/roles" 403 "" true
|
test_api_endpoint "Get Roles List - $fullname" "GET" "/v1/roles" 403 "" true
|
||||||
test_api_endpoint "Get Permissions List - $fullname" "GET" "/v1/permissions" 403 "" true
|
test_api_endpoint "Get Permissions List - $fullname" "GET" "/v1/permissions" 403 "" true
|
||||||
test_api_endpoint "Get Mentors List - $fullname" "GET" "/v1/mentors" 200 "" true
|
test_api_endpoint "Get Mentors List - $fullname" "GET" "/v1/mentors" 200 "" true
|
||||||
@@ -471,7 +487,7 @@ test_comprehensive_with_user() {
|
|||||||
test_api_endpoint "Users with Sort - $fullname" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true
|
test_api_endpoint "Users with Sort - $fullname" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
test_api_endpoint "Users with Sort - $fullname" "GET" "/v1/users?sort_by=created_at&order=DESC" 403 "" true
|
test_api_endpoint "Users with Sort - $fullname" "GET" "/v1/users?sort_by=created_at&order=DESC" 200 "" true
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
@@ -522,7 +538,7 @@ test_authentication_endpoints() {
|
|||||||
|
|
||||||
local forgot_password_data
|
local forgot_password_data
|
||||||
forgot_password_data=$(jq -n --arg email "$TEST_EMAIL" '{email: $email}')
|
forgot_password_data=$(jq -n --arg email "$TEST_EMAIL" '{email: $email}')
|
||||||
test_api_endpoint "Forgot Password Test" "POST" "/v1/auth/forgot" 400 "$forgot_password_data"
|
test_api_endpoint "Forgot Password Test" "POST" "/v1/auth/forgot" 200 "$forgot_password_data"
|
||||||
|
|
||||||
local new_password_data
|
local new_password_data
|
||||||
new_password_data=$(jq -n --arg token "some_reset_token" --arg pass "newpassword123!A" '{token: $token, password: $pass}')
|
new_password_data=$(jq -n --arg token "some_reset_token" --arg pass "newpassword123!A" '{token: $token, password: $pass}')
|
||||||
@@ -602,9 +618,9 @@ test_crud_operations() {
|
|||||||
|
|
||||||
local testimonial_data
|
local testimonial_data
|
||||||
testimonial_data=$(jq -n --arg content "Test testimonial via Bash $(date +%s)" '{role: "Student", content: $content}')
|
testimonial_data=$(jq -n --arg content "Test testimonial via Bash $(date +%s)" '{role: "Student", content: $content}')
|
||||||
local testimonial_response=$(test_api_endpoint "Create Testimonial" "POST" "/v1/cms/landing/testimonials/create" 201 "$testimonial_data" true)
|
local testimonial_response
|
||||||
|
testimonial_response=$(test_api_endpoint "Create Testimonial" "POST" "/v1/cms/landing/testimonials/create" 201 "$testimonial_data" true)
|
||||||
TEST_TESTIMONIAL_ID=$(echo "$testimonial_response" | jq -r '.data.id // empty')
|
TEST_TESTIMONIAL_ID=$(echo "$testimonial_response" | jq -r '.data.id // empty')
|
||||||
write_test_log "INFO" "TEST_TESTIMONIAL_ID: $TEST_TESTIMONIAL_ID"
|
|
||||||
write_test_log "INFO" "Captured Testimonial ID: $TEST_TESTIMONIAL_ID"
|
write_test_log "INFO" "Captured Testimonial ID: $TEST_TESTIMONIAL_ID"
|
||||||
sleep 0.2
|
sleep 0.2
|
||||||
|
|
||||||
@@ -627,7 +643,10 @@ test_crud_operations() {
|
|||||||
end_date: "2025-12-01T16:00:00Z",
|
end_date: "2025-12-01T16:00:00Z",
|
||||||
location: null
|
location: null
|
||||||
}')
|
}')
|
||||||
test_api_endpoint "Create Event" "POST" "/v1/cms/landing/events/create" 201 "$event_data" true
|
local event_response
|
||||||
|
event_response=$(test_api_endpoint "Create Event" "POST" "/v1/cms/landing/events/create" 201 "$event_data" true)
|
||||||
|
TEST_EVENT_ID=$(echo "$event_response" | jq -r '.data.id // empty')
|
||||||
|
write_test_log "INFO" "Captured Event ID: $TEST_EVENT_ID"
|
||||||
}
|
}
|
||||||
|
|
||||||
test_roles_and_permissions() {
|
test_roles_and_permissions() {
|
||||||
@@ -687,8 +706,12 @@ test_events_endpoints() {
|
|||||||
test_api_endpoint "Get Events with Pagination" "GET" "/v1/cms/landing/events?page=1&per_page=5" 200
|
test_api_endpoint "Get Events with Pagination" "GET" "/v1/cms/landing/events?page=1&per_page=5" 200
|
||||||
test_api_endpoint "Get Events with Search" "GET" "/v1/cms/landing/events?search=tech" 200
|
test_api_endpoint "Get Events with Search" "GET" "/v1/cms/landing/events?search=tech" 200
|
||||||
|
|
||||||
local test_event_id="e1a2b3c4-5d6e-7f8g-9h0i-1j2k3l4m5n6o"
|
# Ensure TEST_EVENT_ID is not empty before testing
|
||||||
test_api_endpoint "Get Event By ID" "GET" "/v1/cms/landing/events/detail/$test_event_id" 200
|
if [ -n "$TEST_EVENT_ID" ]; then
|
||||||
|
test_api_endpoint "Get Event By ID" "GET" "/v1/cms/landing/events/detail/$TEST_EVENT_ID" 200
|
||||||
|
else
|
||||||
|
write_test_log "WARN" "✗ Get Event By ID - Dilewati: TEST_EVENT_ID tidak tersedia"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
test_testimonials_endpoints() {
|
test_testimonials_endpoints() {
|
||||||
@@ -803,11 +826,15 @@ fi
|
|||||||
clear_database
|
clear_database
|
||||||
|
|
||||||
printf "\n${CYAN}=== Menjalankan Seeders ===${NC}\n"
|
printf "\n${CYAN}=== Menjalankan Seeders ===${NC}\n"
|
||||||
if ! RUST_LOG=debug cargo run --bin seeder; then
|
if [ "$SKIP_SEED" = true ]; then
|
||||||
write_test_log "ERROR" "Gagal menjalankan seeder roles permissions."
|
write_test_log "INFO" "Melewatkan seeding database."
|
||||||
exit 1
|
else
|
||||||
|
if ! RUST_LOG=debug cargo run --bin seeder; then
|
||||||
|
write_test_log "ERROR" "Gagal menjalankan seeder roles permissions."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
write_test_log "SUCCESS" "Seeders selesai."
|
||||||
fi
|
fi
|
||||||
write_test_log "SUCCESS" "Seeders selesai."
|
|
||||||
|
|
||||||
|
|
||||||
printf "\n${CYAN}=== Menampilkan User yang Tersedia ===${NC}\n"
|
printf "\n${CYAN}=== Menampilkan User yang Tersedia ===${NC}\n"
|
||||||
|
|||||||
@@ -57,13 +57,19 @@ mod auth_login_tests {
|
|||||||
gender: None,
|
gender: None,
|
||||||
birthdate: None,
|
birthdate: None,
|
||||||
domicile: None,
|
domicile: None,
|
||||||
identity_document_url: None,
|
|
||||||
bio: None,
|
bio: None,
|
||||||
last_education: None,
|
last_education: None,
|
||||||
linkedin_url: None,
|
linkedin_url: None,
|
||||||
github_url: None,
|
github_url: None,
|
||||||
cv_url: None,
|
cv_url: None,
|
||||||
portfolio_url: None,
|
portfolio_url: None,
|
||||||
|
website_url: None,
|
||||||
|
twitter_url: None,
|
||||||
|
location: None,
|
||||||
|
skills: None,
|
||||||
|
experience: None,
|
||||||
|
education: None,
|
||||||
|
career_status: None,
|
||||||
role: crate::make_thing("app_roles", &role.id),
|
role: crate::make_thing("app_roles", &role.id),
|
||||||
mentor_id: None,
|
mentor_id: None,
|
||||||
created_at: imphnen_utils::get_iso_date(),
|
created_at: imphnen_utils::get_iso_date(),
|
||||||
|
|||||||
@@ -31,13 +31,19 @@ mod auth_repository_test {
|
|||||||
gender: None,
|
gender: None,
|
||||||
birthdate: None,
|
birthdate: None,
|
||||||
domicile: None,
|
domicile: None,
|
||||||
identity_document_url: None,
|
|
||||||
bio: None,
|
bio: None,
|
||||||
last_education: None,
|
last_education: None,
|
||||||
linkedin_url: None,
|
linkedin_url: None,
|
||||||
github_url: None,
|
github_url: None,
|
||||||
cv_url: None,
|
cv_url: None,
|
||||||
portfolio_url: None,
|
portfolio_url: None,
|
||||||
|
website_url: None,
|
||||||
|
twitter_url: None,
|
||||||
|
location: None,
|
||||||
|
skills: None,
|
||||||
|
experience: None,
|
||||||
|
education: None,
|
||||||
|
career_status: None,
|
||||||
role: make_thing("app_roles", &get_role_id(state).await),
|
role: make_thing("app_roles", &get_role_id(state).await),
|
||||||
mentor_id: None,
|
mentor_id: None,
|
||||||
created_at: get_iso_date(),
|
created_at: get_iso_date(),
|
||||||
@@ -90,13 +96,19 @@ mod auth_repository_test {
|
|||||||
gender: None,
|
gender: None,
|
||||||
birthdate: None,
|
birthdate: None,
|
||||||
domicile: None,
|
domicile: None,
|
||||||
identity_document_url: None,
|
|
||||||
bio: None,
|
bio: None,
|
||||||
last_education: None,
|
last_education: None,
|
||||||
linkedin_url: None,
|
linkedin_url: None,
|
||||||
github_url: None,
|
github_url: None,
|
||||||
cv_url: None,
|
cv_url: None,
|
||||||
portfolio_url: None,
|
portfolio_url: None,
|
||||||
|
website_url: None,
|
||||||
|
twitter_url: None,
|
||||||
|
location: None,
|
||||||
|
skills: None,
|
||||||
|
experience: None,
|
||||||
|
education: None,
|
||||||
|
career_status: None,
|
||||||
role: RolesDetailQueryDto {
|
role: RolesDetailQueryDto {
|
||||||
id: make_thing("app_roles", &Uuid::new_v4().to_string()),
|
id: make_thing("app_roles", &Uuid::new_v4().to_string()),
|
||||||
name: "Dummy Role".into(),
|
name: "Dummy Role".into(),
|
||||||
|
|||||||
Reference in New Issue
Block a user