This commit is contained in:
2025-10-24 14:54:44 -05:00
parent cb06217ef7
commit 6a58e19b10
16 changed files with 1172 additions and 138 deletions

View File

@@ -0,0 +1,15 @@
<?hh // strict
namespace App\Controllers;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class ApplicationController
{
public function apply(Request $request, Response $response): Response
{
$response->getBody()->write(json_encode(['message' => 'Apply for job endpoint']));
return $response->withHeader('Content-Type', 'application/json');
}
}

View File

@@ -2,26 +2,166 @@
namespace App\Controllers;
use App\Services\AuthService;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class AuthController
{
private AuthService $authService;
public function __construct()
{
$this->authService = new AuthService();
}
public function login(Request $request, Response $response): Response
{
$response->getBody()->write(json_encode(['message' => 'Login endpoint']));
// For traditional login, you would validate credentials here
// For OIDC/social login, redirect to appropriate provider
$params = $request->getParsedBody();
$provider = $params['provider'] ?? null;
switch ($provider) {
case 'google':
$authUrl = $this->authService->getGoogleAuthorizationUrl();
$response->getBody()->write(json_encode(['redirect_url' => $authUrl]));
break;
case 'github':
$authUrl = $this->authService->getGithubAuthorizationUrl();
$response->getBody()->write(json_encode(['redirect_url' => $authUrl]));
break;
default:
// Traditional login
$email = $params['email'] ?? '';
$password = $params['password'] ?? '';
// Validate credentials (simplified)
if ($this->validateCredentials($email, $password)) {
$token = $this->generateToken($email);
$response->getBody()->write(json_encode(['token' => $token, 'message' => 'Login successful']));
} else {
$response = $response->withStatus(401);
$response->getBody()->write(json_encode(['error' => 'Invalid credentials']));
}
break;
}
return $response->withHeader('Content-Type', 'application/json');
}
public function logout(Request $request, Response $response): Response
{
$response->getBody()->write(json_encode(['message' => 'Logout endpoint']));
// Clear any tokens, sessions, etc.
$response->getBody()->write(json_encode(['message' => 'Logout successful']));
return $response->withHeader('Content-Type', 'application/json');
}
public function register(Request $request, Response $response): Response
{
$response->getBody()->write(json_encode(['message' => 'Register endpoint']));
$params = $request->getParsedBody();
$email = $params['email'] ?? '';
$name = $params['name'] ?? '';
$password = $params['password'] ?? '';
// Validate input
if (empty($email) || empty($name) || empty($password)) {
$response = $response->withStatus(400);
$response->getBody()->write(json_encode(['error' => 'All fields are required']));
return $response->withHeader('Content-Type', 'application/json');
}
// Register user (simplified)
if ($this->registerUser($email, $name, $password)) {
$token = $this->generateToken($email);
$response->getBody()->write(json_encode(['token' => $token, 'message' => 'Registration successful']));
} else {
$response = $response->withStatus(500);
$response->getBody()->write(json_encode(['error' => 'Registration failed']));
}
return $response->withHeader('Content-Type', 'application/json');
}
public function googleCallback(Request $request, Response $response): Response
{
try {
$userData = $this->authService->handleGoogleCallback($request);
// Check if user exists, create if not
$user = $this->findOrCreateUser($userData);
// Generate JWT token
$token = $this->generateToken($user['email']);
// Redirect to frontend with token
$redirectUrl = $_ENV['FRONTEND_URL'] ?? 'http://localhost:3000' . "/auth/callback?token={$token}";
return $response->withHeader('Location', $redirectUrl)->withStatus(302);
} catch (\Exception $e) {
$response = $response->withStatus(500);
$response->getBody()->write(json_encode(['error' => $e->getMessage()]));
return $response->withHeader('Content-Type', 'application/json');
}
}
public function githubCallback(Request $request, Response $response): Response
{
try {
$userData = $this->authService->handleGithubCallback($request);
// Check if user exists, create if not
$user = $this->findOrCreateUser($userData);
// Generate JWT token
$token = $this->generateToken($user['email']);
// Redirect to frontend with token
$redirectUrl = $_ENV['FRONTEND_URL'] ?? 'http://localhost:3000' . "/auth/callback?token={$token}";
return $response->withHeader('Location', $redirectUrl)->withStatus(302);
} catch (\Exception $e) {
$response = $response->withStatus(500);
$response->getBody()->write(json_encode(['error' => $e->getMessage()]));
return $response->withHeader('Content-Type', 'application/json');
}
}
private function validateCredentials(string $email, string $password): bool
{
// This would normally check against a database
// For now, just return true for demo purposes
return !empty($email) && !empty($password);
}
private function registerUser(string $email, string $name, string $password): bool
{
// This would normally store the user in a database
// For now, just return true for demo purposes
return true;
}
private function findOrCreateUser(array $userData): array
{
// This would normally query the database to find or create a user
// For now, return mock user data
return [
'id' => 1,
'email' => $userData['email'],
'name' => $userData['name'],
];
}
private function generateToken(string $email): string
{
$payload = [
'iss' => 'MerchantsOfHope', // Issuer
'sub' => $email, // Subject
'iat' => time(), // Issued at
'exp' => time() + 3600 // Expiration time (1 hour)
];
return JWT::encode($payload, $_ENV['JWT_SECRET'], 'HS256');
}
}

View File

@@ -2,47 +2,220 @@
namespace App\Controllers;
use App\Models\Job;
use App\Services\JobService;
use PDO;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class JobController
{
private JobService $jobService;
public function __construct()
{
// In a real application, this would be injected via DI container
$this->jobService = new JobService($this->getDbConnection());
}
public function listJobs(Request $request, Response $response): Response
{
$response->getBody()->write(json_encode(['message' => 'List jobs endpoint']));
// Extract filters from query parameters
$params = $request->getQueryParams();
$filters = [];
if (isset($params['location'])) {
$filters['location'] = $params['location'];
}
if (isset($params['keywords'])) {
$filters['keywords'] = $params['keywords'];
}
// Get tenant from request attribute (set by middleware)
$tenant = $request->getAttribute('tenant');
$jobs = $this->jobService->getAllJobs($tenant, $filters);
$jobsArray = [];
foreach ($jobs as $job) {
$jobsArray[] = [
'id' => $job->getId(),
'title' => $job->getTitle(),
'description' => $job->getDescription(),
'location' => $job->getLocation(),
'employment_type' => $job->getEmploymentType(),
'created_at' => $job->getCreatedAt()->format('Y-m-d H:i:s')
];
}
$response->getBody()->write(json_encode($jobsArray));
return $response->withHeader('Content-Type', 'application/json');
}
public function getJob(Request $request, Response $response, array $args): Response
{
$jobId = $args['id'];
$response->getBody()->write(json_encode(['message' => 'Get job endpoint', 'id' => $jobId]));
$jobId = (int)$args['id'];
// Get tenant from request attribute (set by middleware)
$tenant = $request->getAttribute('tenant');
$job = $this->jobService->getJobById($jobId, $tenant);
if (!$job) {
$response = $response->withStatus(404);
$response->getBody()->write(json_encode(['error' => 'Job not found']));
return $response->withHeader('Content-Type', 'application/json');
}
$jobData = [
'id' => $job->getId(),
'title' => $job->getTitle(),
'description' => $job->getDescription(),
'location' => $job->getLocation(),
'employment_type' => $job->getEmploymentType(),
'created_at' => $job->getCreatedAt()->format('Y-m-d H:i:s'),
'updated_at' => $job->getUpdatedAt()->format('Y-m-d H:i:s')
];
$response->getBody()->write(json_encode($jobData));
return $response->withHeader('Content-Type', 'application/json');
}
public function myJobs(Request $request, Response $response): Response
{
$response->getBody()->write(json_encode(['message' => 'My jobs endpoint']));
// Get tenant from request attribute (set by middleware)
$tenant = $request->getAttribute('tenant');
// For job providers, get jobs they've posted
// This would typically involve checking user permissions
// For now, just return all jobs for the tenant
$jobs = $this->jobService->getAllJobs($tenant);
$jobsArray = [];
foreach ($jobs as $job) {
$jobsArray[] = [
'id' => $job->getId(),
'title' => $job->getTitle(),
'description' => $job->getDescription(),
'location' => $job->getLocation(),
'employment_type' => $job->getEmploymentType(),
'created_at' => $job->getCreatedAt()->format('Y-m-d H:i:s')
];
}
$response->getBody()->write(json_encode($jobsArray));
return $response->withHeader('Content-Type', 'application/json');
}
public function createJob(Request $request, Response $response): Response
{
$response->getBody()->write(json_encode(['message' => 'Create job endpoint']));
return $response->withHeader('Content-Type', 'application/json');
$params = $request->getParsedBody();
// Validate required fields
$required = ['title', 'description', 'location', 'employment_type'];
foreach ($required as $field) {
if (empty($params[$field])) {
$response = $response->withStatus(400);
$response->getBody()->write(json_encode(['error' => "Missing required field: {$field}"]));
return $response->withHeader('Content-Type', 'application/json');
}
}
// Get tenant from request attribute (set by middleware)
$tenant = $request->getAttribute('tenant');
$tenantId = $tenant ? $tenant->getId() : 'default';
// Create job
$job = new Job(
id: 0, // Will be set by database
title: $params['title'],
description: $params['description'],
location: $params['location'],
employmentType: $params['employment_type'],
tenantId: $tenantId
);
$result = $this->jobService->createJob($job);
if ($result) {
$response->getBody()->write(json_encode(['message' => 'Job created successfully']));
return $response->withHeader('Content-Type', 'application/json')->withStatus(201);
} else {
$response = $response->withStatus(500);
$response->getBody()->write(json_encode(['error' => 'Failed to create job']));
return $response->withHeader('Content-Type', 'application/json');
}
}
public function updateJob(Request $request, Response $response, array $args): Response
{
$jobId = $args['id'];
$response->getBody()->write(json_encode(['message' => 'Update job endpoint', 'id' => $jobId]));
return $response->withHeader('Content-Type', 'application/json');
$jobId = (int)$args['id'];
$params = $request->getParsedBody();
// Get tenant from request attribute (set by middleware)
$tenant = $request->getAttribute('tenant');
// First get the existing job to ensure it belongs to this tenant
$existingJob = $this->jobService->getJobById($jobId, $tenant);
if (!$existingJob) {
$response = $response->withStatus(404);
$response->getBody()->write(json_encode(['error' => 'Job not found or does not belong to your tenant']));
return $response->withHeader('Content-Type', 'application/json');
}
// Update the job with new data
$existingJob->setTitle($params['title'] ?? $existingJob->getTitle());
$existingJob->setDescription($params['description'] ?? $existingJob->getDescription());
$existingJob->setLocation($params['location'] ?? $existingJob->getLocation());
$existingJob->setEmploymentType($params['employment_type'] ?? $existingJob->getEmploymentType());
$result = $this->jobService->updateJob($existingJob);
if ($result) {
$response->getBody()->write(json_encode(['message' => 'Job updated successfully']));
return $response->withHeader('Content-Type', 'application/json');
} else {
$response = $response->withStatus(500);
$response->getBody()->write(json_encode(['error' => 'Failed to update job']));
return $response->withHeader('Content-Type', 'application/json');
}
}
public function deleteJob(Request $request, Response $response, array $args): Response
{
$jobId = $args['id'];
$response->getBody()->write(json_encode(['message' => 'Delete job endpoint', 'id' => $jobId]));
return $response->withHeader('Content-Type', 'application/json');
$jobId = (int)$args['id'];
// Get tenant from request attribute (set by middleware)
$tenant = $request->getAttribute('tenant');
$result = $this->jobService->deleteJob($jobId, $tenant);
if ($result) {
$response->getBody()->write(json_encode(['message' => 'Job deleted successfully']));
return $response->withHeader('Content-Type', 'application/json');
} else {
$response = $response->withStatus(404);
$response->getBody()->write(json_encode(['error' => 'Job not found or does not belong to your tenant']));
return $response->withHeader('Content-Type', 'application/json');
}
}
private function getDbConnection(): PDO
{
// In a real application, this would be configured properly
$host = $_ENV['DB_HOST'] ?? 'localhost';
$dbname = $_ENV['DB_NAME'] ?? 'moh';
$username = $_ENV['DB_USER'] ?? 'moh_user';
$password = $_ENV['DB_PASS'] ?? 'moh_password';
$port = $_ENV['DB_PORT'] ?? '5432';
$dsn = "pgsql:host={$host};port={$port};dbname={$dbname};";
return new PDO($dsn, $username, $password, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
}
}