Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions api/src/Controllers/LikeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Flight;
use Matcha\Api\Enums\NotificationType;
use Matcha\Api\Model\User;
use Matcha\Api\Services\FameCalculator;

class LikeController
{
Expand All @@ -20,6 +21,11 @@ public function store(string $username)
}

$me->like($target);
try {
(new FameCalculator($me, $target))->onLike();
} catch (\Throwable $e) {
// calcul error
}

if ($target->hasMatch($me->username)) {
$notif = [
Expand Down Expand Up @@ -62,6 +68,11 @@ public function destroy(string $username)
}

$me->unlike($user);
try {
(new FameCalculator($me, $user))->onUnLike();
} catch (\Throwable $e) {
// calcul error
}

Flight::json([], 203);
}
Expand Down
14 changes: 13 additions & 1 deletion api/src/Controllers/PassController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@

use Flight;
use Matcha\Api\Model\User;
use Matcha\Api\Model\Pass;
use Matcha\Api\Services\FameCalculator;
use Matcha\Api\Exceptions\UniqueConstraintException;

class PassController
{
public function store(string $username)
{
$target = User::find(['username' => $username]);
$me = Flight::user();

if (is_null($target)) {
Flight::json([
Expand All @@ -19,8 +23,16 @@ public function store(string $username)
return;
}

Flight::user()->pass($target);
try {
$me->pass($target);
(new FameCalculator($me, $target))->onPass();
} catch (UniqueConstraintException $e) {
$pass = Pass::find(['user_id' => $me->id, 'target_id' => $target->id]);

$pass->created_at = date('Y-m-d H:i:s');

$pass->update(['user_id' => $me->id, 'target_id' => $target->id]);
}
Flight::json(['success' => true,], 204);
}
}
6 changes: 6 additions & 0 deletions api/src/Controllers/ViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Flight;
use Matcha\Api\Enums\NotificationType;
use Matcha\Api\Model\User;
use Matcha\Api\Services\FameCalculator;

class ViewController
{
Expand All @@ -30,6 +31,11 @@ public function store(string $username)
}

$me->view($user);
try {
(new FameCalculator($me, $user))->onView();
} catch (\Throwable $e) {
// calcul error
}

Flight::notifier()->notify($user, [
'type' => NotificationType::VIEW,
Expand Down
13 changes: 11 additions & 2 deletions api/src/Model/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,18 @@ public function save(): Model
return $this->id > 0 ? $this->update() : $this->create();
}

private function update(): Model
public function update(array $where = []): Model
{
$data = $this->getData();

if (empty($where)) {
$where = ['id' => $this->id];
}

$whereList = array_map(function ($k, $v) {
return $k . " = " . $v;
}, array_keys($where), $where);

$sqlQuery = "UPDATE " . $this->getTable()
. " SET " . implode(
", ",
Expand All @@ -55,7 +64,7 @@ private function update(): Model
array_values($data)
)
)
. ' WHERE id = ' . $this->id;
. ' WHERE ' . implode(" AND ", $whereList);

self::db()->exec($sqlQuery);
$this->reload();
Expand Down
65 changes: 65 additions & 0 deletions api/src/Services/FameCalculator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace Matcha\Api\Services;

use Exception;
use Matcha\Api\Model\User;
use Flight;

class FameCalculator
{
private const K_LIKE = 12;
private const K_PASS = 8;
private const K_VIEW = 2;

private const MIN_FAME = 0;
private const MAX_FAME = 2500;

public function __construct(
private User $actor, // liker
private User $target // liked
) {
}

public function onLike(): void
{
$this->save(self::K_LIKE * (1 - $this->expected()));
}

public function onUnLike(): void
{
$this->save(-self::K_LIKE * (1 - $this->expected()));
}

public function onPass(): void
{
$this->save(-self::K_PASS * $this->expected());
}

public function onView(): void
{
$this->save(self::K_VIEW * (1 - $this->expected()));
}

private function expected(): float
{
$diff = $this->actor->fame_rating - $this->target->fame_rating;

return 1 / (1 + 10 ** ($diff / 400));
}

private function save(float $delta): void
{
$stmt = Flight::db()->prepare(
'UPDATE users
SET fame_rating = LEAST(:max, GREATEST(:min, fame_rating + :delta))
WHERE id = :id'
);
$stmt->execute([
'max' => self::MAX_FAME,
'min' => self::MIN_FAME,
'delta' => $delta,
'id' => $this->target->id,
]);
}
}
6 changes: 6 additions & 0 deletions frontend/src/api/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,10 @@ export const usersApi = {
res.json(),
)
},

async view(username: string) {
return ApiClient.post(`/users/${username}/view`).then(res =>
res.json(),
)
},
}
10 changes: 10 additions & 0 deletions frontend/src/composable/useUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ export function useUsers() {
}
}

const view = async (who: string) => {
error.value = null
try {
await usersApi.view(who)
} catch (err: any) {
error.value = err.response?.data?.message || "You can't view this user."
}
}

// --- Modération (Blocages et Signalement) ---
const fetchBlockedList = async () => {
isLoading.value = true
Expand Down Expand Up @@ -180,5 +189,6 @@ export function useUsers() {
suggestion,
suggestionReset,
pass,
view,
}
}
13 changes: 9 additions & 4 deletions frontend/src/views/UserProfileView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
DialogFooter,
} from '@/components/ui/dialog'
import { ApiClient } from '@/api/client'
import { useUsers } from '@/composable/useUsers'

interface Profile {
id: number
Expand All @@ -32,7 +33,7 @@ interface Profile {
city: string | null
biography: string | null
avatar: string | null
photos: { id: number; path: string }[]
photos: string []
tags: string[]
liked_by_me: boolean
is_match: boolean
Expand All @@ -49,6 +50,7 @@ const error = ref('')
const showMatch = ref(false)
const editing = ref(false)
const form = ref({ bio: '', city: '', tags: '' })
const useUser = useUsers()

async function load() {
loading.value = true
Expand Down Expand Up @@ -110,7 +112,10 @@ async function saveProfile() {

const initials = (name: string) => name.slice(0, 2).toUpperCase()

onMounted(load)
onMounted(() => {
load()
useUser.view(`${route.params.username}`);
})
watch(() => route.params.id, load)
</script>

Expand All @@ -133,9 +138,9 @@ watch(() => route.params.id, load)
<Card class="overflow-hidden">
<Carousel v-if="profile.photos.length" class="w-full">
<CarouselContent>
<CarouselItem v-for="p in profile.photos" :key="p.id">
<CarouselItem v-for="(p, index) in profile.photos" :key="index">
<img
:src="p.path"
:src="p"
:alt="profile.username"
class="w-full aspect-3/4 object-cover"
/>
Expand Down
Loading