refactor: implemented privacy checks in the GetProfileByUsername method;
refactor: reworked sql request for privacy-checking profile getter
This commit is contained in:
@@ -345,59 +345,63 @@ func (q *Queries) GetProfileByUsername(ctx context.Context, username string) (Pr
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getProfileByUsernameRestricted = `-- name: GetProfileByUsernameRestricted :one
|
||||
const getProfileByUsernameWithPrivacy = `-- name: GetProfileByUsernameWithPrivacy :one
|
||||
SELECT
|
||||
users.username,
|
||||
profiles.name,
|
||||
CASE
|
||||
WHEN profile_settings.hide_birthday OR profile_settings.hide_profile_details THEN NULL
|
||||
ELSE profiles.birthday
|
||||
END AS birthday,
|
||||
CASE
|
||||
WHEN profile_settings.hide_profile_details THEN NULL
|
||||
ELSE profiles.bio
|
||||
END AS bio,
|
||||
CASE
|
||||
WHEN profile_settings.hide_profile_details THEN NULL
|
||||
ELSE profiles.avatar_url
|
||||
END AS avatar_url,
|
||||
profiles.color,
|
||||
profiles.color_grad,
|
||||
profile_settings.hide_profile_details
|
||||
FROM profiles
|
||||
JOIN users ON users.id = profiles.user_id
|
||||
JOIN profile_settings ON profiles.id = profile_settings.profile_id
|
||||
WHERE users.username = $1 AND ($2 IS FALSE OR profile_settings.hide_for_unauthenticated IS FALSE)
|
||||
u.username,
|
||||
p.name,
|
||||
p.bio,
|
||||
p.avatar_url,
|
||||
CASE WHEN ps.hide_birthday THEN NULL ELSE p.birthday END AS birthday,
|
||||
p.color,
|
||||
p.color_grad,
|
||||
NOT ($1::text = '' AND ps.hide_for_unauthenticated) AS access_allowed
|
||||
FROM
|
||||
users AS u
|
||||
JOIN profiles AS p ON u.id = p.user_id
|
||||
JOIN profile_settings AS ps ON p.id = ps.profile_id
|
||||
WHERE
|
||||
u.username = $2::text
|
||||
AND (
|
||||
$2::text = $1::text
|
||||
OR
|
||||
u.deleted IS FALSE
|
||||
AND u.verified IS TRUE
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM banned_users
|
||||
WHERE user_id = u.id
|
||||
)
|
||||
)
|
||||
`
|
||||
|
||||
type GetProfileByUsernameRestrictedParams struct {
|
||||
Username string
|
||||
Column2 *bool
|
||||
type GetProfileByUsernameWithPrivacyParams struct {
|
||||
Requester string
|
||||
SearchedUsername string
|
||||
}
|
||||
|
||||
type GetProfileByUsernameRestrictedRow struct {
|
||||
type GetProfileByUsernameWithPrivacyRow struct {
|
||||
Username string
|
||||
Name string
|
||||
Bio string
|
||||
AvatarUrl string
|
||||
Birthday pgtype.Timestamp
|
||||
Bio *string
|
||||
AvatarUrl *string
|
||||
Color string
|
||||
ColorGrad string
|
||||
HideProfileDetails bool
|
||||
AccessAllowed *bool
|
||||
}
|
||||
|
||||
func (q *Queries) GetProfileByUsernameRestricted(ctx context.Context, arg GetProfileByUsernameRestrictedParams) (GetProfileByUsernameRestrictedRow, error) {
|
||||
row := q.db.QueryRow(ctx, getProfileByUsernameRestricted, arg.Username, arg.Column2)
|
||||
var i GetProfileByUsernameRestrictedRow
|
||||
func (q *Queries) GetProfileByUsernameWithPrivacy(ctx context.Context, arg GetProfileByUsernameWithPrivacyParams) (GetProfileByUsernameWithPrivacyRow, error) {
|
||||
row := q.db.QueryRow(ctx, getProfileByUsernameWithPrivacy, arg.Requester, arg.SearchedUsername)
|
||||
var i GetProfileByUsernameWithPrivacyRow
|
||||
err := row.Scan(
|
||||
&i.Username,
|
||||
&i.Name,
|
||||
&i.Birthday,
|
||||
&i.Bio,
|
||||
&i.AvatarUrl,
|
||||
&i.Birthday,
|
||||
&i.Color,
|
||||
&i.ColorGrad,
|
||||
&i.HideProfileDetails,
|
||||
&i.AccessAllowed,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ func (p *profileServiceImpl) GetMyProfile(cinfo dto.ClientInfo) (*dto.ProfileDto
|
||||
return profileDto, nil
|
||||
}
|
||||
|
||||
// TODO: Profile privacy settings checks
|
||||
func (p *profileServiceImpl) GetProfileByUsername(cinfo dto.ClientInfo, username string) (*dto.ProfileDto, error) {
|
||||
helper, db, err := database.NewDbHelperTransaction(p.dbctx); if err != nil {
|
||||
p.log.Error(
|
||||
@@ -80,7 +79,10 @@ func (p *profileServiceImpl) GetProfileByUsername(cinfo dto.ClientInfo, username
|
||||
}
|
||||
defer helper.Rollback()
|
||||
|
||||
profile, err := db.TXQueries.GetProfileByUsername(db.CTX, username); if err != nil {
|
||||
profileRow, err := db.TXQueries.GetProfileByUsernameWithPrivacy(db.CTX, database.GetProfileByUsernameWithPrivacyParams{
|
||||
Requester: cinfo.Username,
|
||||
SearchedUsername: username,
|
||||
}); if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, errs.ErrNotFound
|
||||
}
|
||||
@@ -92,8 +94,18 @@ func (p *profileServiceImpl) GetProfileByUsername(cinfo dto.ClientInfo, username
|
||||
return nil, errs.ErrServerError
|
||||
}
|
||||
|
||||
profileDto := &dto.ProfileDto{}
|
||||
mapspecial.MapProfileDto(profile, profileDto)
|
||||
if !*profileRow.AccessAllowed {
|
||||
return nil, errs.ErrForbidden
|
||||
}
|
||||
|
||||
profileDto := &dto.ProfileDto{
|
||||
Name: profileRow.Name,
|
||||
Bio: profileRow.Bio,
|
||||
AvatarUrl: &profileRow.AvatarUrl,
|
||||
Birthday: profileRow.Birthday.Time.UnixMilli(),
|
||||
Color: profileRow.Color,
|
||||
ColorGrad: profileRow.ColorGrad,
|
||||
}
|
||||
|
||||
return profileDto, nil
|
||||
}
|
||||
|
||||
@@ -296,29 +296,33 @@ SELECT profiles.* FROM profiles
|
||||
JOIN users ON users.id = profiles.user_id
|
||||
WHERE users.username = $1;
|
||||
|
||||
;-- name: GetProfileByUsernameRestricted :one
|
||||
;-- name: GetProfileByUsernameWithPrivacy :one
|
||||
SELECT
|
||||
users.username,
|
||||
profiles.name,
|
||||
CASE
|
||||
WHEN profile_settings.hide_birthday OR profile_settings.hide_profile_details THEN NULL
|
||||
ELSE profiles.birthday
|
||||
END AS birthday,
|
||||
CASE
|
||||
WHEN profile_settings.hide_profile_details THEN NULL
|
||||
ELSE profiles.bio
|
||||
END AS bio,
|
||||
CASE
|
||||
WHEN profile_settings.hide_profile_details THEN NULL
|
||||
ELSE profiles.avatar_url
|
||||
END AS avatar_url,
|
||||
profiles.color,
|
||||
profiles.color_grad,
|
||||
profile_settings.hide_profile_details
|
||||
FROM profiles
|
||||
JOIN users ON users.id = profiles.user_id
|
||||
JOIN profile_settings ON profiles.id = profile_settings.profile_id
|
||||
WHERE users.username = $1 AND ($2 IS FALSE OR profile_settings.hide_for_unauthenticated IS FALSE);
|
||||
u.username,
|
||||
p.name,
|
||||
p.bio,
|
||||
p.avatar_url,
|
||||
CASE WHEN ps.hide_birthday THEN NULL ELSE p.birthday END AS birthday,
|
||||
p.color,
|
||||
p.color_grad,
|
||||
NOT (@requester::text = '' AND ps.hide_for_unauthenticated) AS access_allowed
|
||||
FROM
|
||||
users AS u
|
||||
JOIN profiles AS p ON u.id = p.user_id
|
||||
JOIN profile_settings AS ps ON p.id = ps.profile_id
|
||||
WHERE
|
||||
u.username = @searched_username::text
|
||||
AND (
|
||||
@searched_username::text = @requester::text
|
||||
OR
|
||||
u.deleted IS FALSE
|
||||
AND u.verified IS TRUE
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM banned_users
|
||||
WHERE user_id = u.id
|
||||
)
|
||||
);
|
||||
|
||||
;-- name: GetProfilesRestricted :many
|
||||
SELECT
|
||||
|
||||
Reference in New Issue
Block a user