Updated Google Scholar Integration,Updated Admin and HOD Dashboard, Added Google Auth: Login Controller and Routes
This commit is contained in:
@@ -15,7 +15,9 @@ class GoogleController extends Controller
|
||||
*/
|
||||
public function redirectToGoogle()
|
||||
{
|
||||
return Socialite::driver('google')->redirect();
|
||||
// Prefer to hint Google to show accounts from the somaiya.edu domain.
|
||||
// This is only a UI hint — always validate the domain on the callback.
|
||||
return Socialite::driver('google')->with(['hd' => 'somaiya.edu'])->redirect();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,10 +28,20 @@ class GoogleController extends Controller
|
||||
try {
|
||||
$googleUser = Socialite::driver('google')->user();
|
||||
|
||||
// Validate that the user belongs to the somaiya.edu domain.
|
||||
// Google may return a 'hd' (hosted domain) claim; fall back to parsing the email.
|
||||
$email = $googleUser->getEmail();
|
||||
$hostedDomain = data_get($googleUser->user, 'hd');
|
||||
$domain = $hostedDomain ?: (strpos($email, '@') !== false ? substr(strrchr($email, "@"), 1) : null);
|
||||
|
||||
if ($domain !== 'somaiya.edu') {
|
||||
return redirect()->route('login')->withErrors(['error' => 'Please sign in using a somaiya.edu account.']);
|
||||
}
|
||||
|
||||
$user = User::firstOrCreate(
|
||||
['email' => $googleUser->getEmail()],
|
||||
['email' => $email],
|
||||
[
|
||||
'name' => $googleUser->getName(),
|
||||
'name' => $googleUser->getName() ?: $email,
|
||||
'password' => bcrypt(Str::random(16)), // Generate a random password
|
||||
]
|
||||
);
|
||||
|
||||
@@ -2,57 +2,392 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use App\Models\ActivitiesAttended;
|
||||
use App\Models\ActivitiesOrganised;
|
||||
use App\Models\BooksPublished;
|
||||
use App\Models\Department;
|
||||
use App\Models\ExternalEngagement;
|
||||
use App\Models\IvOrganised;
|
||||
use App\Models\OnlineCourse;
|
||||
use App\Models\Patent;
|
||||
use App\Models\Publication;
|
||||
use App\Services\ProofDownloadService;
|
||||
use Illuminate\Http\Request;
|
||||
// use Yajra\DataTables\Facades\DataTables;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class CoordinatorController extends Controller
|
||||
{
|
||||
// Coordinator dashboard (optional)
|
||||
public function index()
|
||||
{
|
||||
return view('coordinator.dashboard');
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
|
||||
// Collect distinct years from all relevant date fields
|
||||
$years = collect([
|
||||
ActivitiesAttended::where('department_id', $user->department_id) ->selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'),
|
||||
|
||||
ActivitiesOrganised::where('department_id', $user->department_id) ->selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'),
|
||||
|
||||
BooksPublished::where('department_id', $user->department_id) ->selectRaw('YEAR(date_of_publication) as year')->distinct()->pluck('year'),
|
||||
|
||||
ExternalEngagement::where('department_id', $user->department_id) ->selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'),
|
||||
|
||||
IvOrganised::where('department_id', $user->department_id) ->selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'),
|
||||
|
||||
OnlineCourse::where('department_id', $user->department_id) ->selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'),
|
||||
|
||||
Patent::where('department_id', $user->department_id) ->selectRaw('YEAR(date_of_submission) as year')->distinct()->pluck('year'),
|
||||
|
||||
Publication::where('department_id', $user->department_id) ->selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'),
|
||||
|
||||
])->flatten()->filter()->unique()->sortDesc()->values();
|
||||
|
||||
return view('coordinator.dashboard', compact('departments', 'years'));
|
||||
}
|
||||
|
||||
// View responses submitted by users
|
||||
public function viewActivitiesAttendedResponses()
|
||||
{
|
||||
$departments = Department::all();
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
return view('pages.activities-attended.index', compact('departments'));
|
||||
}
|
||||
|
||||
public function viewActivitiesOrganisedResponses()
|
||||
{
|
||||
return view('pages.activities-organised.index');
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
return view('pages.activities-organised.index', compact('departments'));
|
||||
}
|
||||
|
||||
public function viewIvOrganisedResponses()
|
||||
{
|
||||
return view('pages.iv-organised.index');
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
return view('pages.iv-organised.index', compact('departments'));
|
||||
}
|
||||
|
||||
public function viewPublicationsResponses()
|
||||
{
|
||||
return view('pages.publications.index');
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
return view('pages.publications.index', compact('departments'));
|
||||
}
|
||||
|
||||
public function viewBooksPublishedResponses()
|
||||
{
|
||||
return view('pages.booksPublished.index');
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
return view('pages.booksPublished.index', compact('departments'));
|
||||
}
|
||||
|
||||
public function viewExternalEngagementResponses()
|
||||
{
|
||||
return view('pages.externalEngagement.index');
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
return view('pages.externalEngagement.index', compact('departments'));
|
||||
}
|
||||
|
||||
public function viewOnlineCoursesResponses()
|
||||
{
|
||||
return view('pages.onlineCourses.index');
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
return view('pages.onlineCourses.index', compact('departments'));
|
||||
}
|
||||
|
||||
public function viewPatentsResponses()
|
||||
{
|
||||
return view('pages.patents.index');
|
||||
$user = Auth::user();
|
||||
$departments = Department::where('id', $user->department_id)->get();
|
||||
return view('pages.patents.index', compact('departments'));
|
||||
}
|
||||
|
||||
public function downloadProofs(Request $request, ProofDownloadService $proofDownloadService)
|
||||
{
|
||||
// Validate the request
|
||||
$request->validate([
|
||||
'ids' => 'required|string',
|
||||
'model' => 'sometimes|string',
|
||||
]);
|
||||
|
||||
$ids = json_decode($request->input('ids'));
|
||||
$modelName = $request->input('model', 'ActivitiesAttended');
|
||||
|
||||
// Model mapping
|
||||
$modelMap = [
|
||||
'ActivitiesAttended' => ActivitiesAttended::class,
|
||||
'ActivitiesOrganised' => ActivitiesOrganised::class,
|
||||
'IvOrganised' => IvOrganised::class,
|
||||
'Publication' => Publication::class,
|
||||
'BooksPublished' => BooksPublished::class,
|
||||
'ExternalEngagement' => ExternalEngagement::class,
|
||||
'OnlineCourse' => OnlineCourse::class,
|
||||
'Patent' => Patent::class,
|
||||
];
|
||||
|
||||
// Get the model class from the map or default to ActivitiesAttended
|
||||
$modelClass = $modelMap[$modelName] ?? ActivitiesAttended::class;
|
||||
|
||||
$result = $proofDownloadService->downloadProofs($modelClass, $ids);
|
||||
|
||||
if (isset($result['error'])) {
|
||||
return back()->with('error', $result['error']);
|
||||
}
|
||||
|
||||
// Return the zip file as a download
|
||||
return response()->download($result['filePath'], $result['fileName'])->deleteFileAfterSend(true);
|
||||
}
|
||||
|
||||
public function analyticsActivitiesAttended()
|
||||
{
|
||||
$data = ActivitiesAttended::selectRaw('departments.name as department, COUNT(*) as count')
|
||||
->join('departments', 'activities_attendeds.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name')
|
||||
->get();
|
||||
|
||||
$total = $data->sum('count');
|
||||
|
||||
return response()->json([
|
||||
'labels' => $data->pluck('department'),
|
||||
'values' => $data->pluck('count'),
|
||||
'total' => $total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsActivitiesOrganised()
|
||||
{
|
||||
$data = ActivitiesOrganised::selectRaw('departments.name as department, COUNT(*) as count')
|
||||
->join('departments', 'activities_organiseds.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name')
|
||||
->get();
|
||||
|
||||
$total = $data->sum('count');
|
||||
|
||||
return response()->json([
|
||||
'labels' => $data->pluck('department'),
|
||||
'values' => $data->pluck('count'),
|
||||
'total' => $total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsIvOrganised()
|
||||
{
|
||||
$data = IvOrganised::selectRaw('departments.name as department, COUNT(*) as count')
|
||||
->join('departments', 'iv_organiseds.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name')
|
||||
->get();
|
||||
|
||||
$total = $data->sum('count');
|
||||
|
||||
return response()->json([
|
||||
'labels' => $data->pluck('department'),
|
||||
'values' => $data->pluck('count'),
|
||||
'total' => $total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsPaperPublished()
|
||||
{
|
||||
$data = Publication::selectRaw('departments.name as department, COUNT(*) as count')
|
||||
->join('departments', 'publications.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name')
|
||||
->get();
|
||||
|
||||
$total = $data->sum('count');
|
||||
|
||||
return response()->json([
|
||||
'labels' => $data->pluck('department'),
|
||||
'values' => $data->pluck('count'),
|
||||
'total' => $total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsBooksPublished()
|
||||
{
|
||||
$data = BooksPublished::selectRaw('departments.name as department, COUNT(*) as count')
|
||||
->join('departments', 'books_published.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name')
|
||||
->get();
|
||||
|
||||
$total = $data->sum('count');
|
||||
|
||||
return response()->json([
|
||||
'labels' => $data->pluck('department'),
|
||||
'values' => $data->pluck('count'),
|
||||
'total' => $total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsExternalEngagement()
|
||||
{
|
||||
$data = ExternalEngagement::selectRaw('departments.name as department, COUNT(*) as count')
|
||||
->join('departments', 'external_engagements.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name')
|
||||
->get();
|
||||
|
||||
$total = $data->sum('count');
|
||||
|
||||
return response()->json([
|
||||
'labels' => $data->pluck('department'),
|
||||
'values' => $data->pluck('count'),
|
||||
'total' => $total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsOnlineCourse()
|
||||
{
|
||||
$data = OnlineCourse::selectRaw('departments.name as department, COUNT(*) as count')
|
||||
->join('departments', 'online_courses.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name')
|
||||
->get();
|
||||
|
||||
$total = $data->sum('count');
|
||||
|
||||
return response()->json([
|
||||
'labels' => $data->pluck('department'),
|
||||
'values' => $data->pluck('count'),
|
||||
'total' => $total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsPatent()
|
||||
{
|
||||
$data = Patent::selectRaw('departments.name as department, COUNT(*) as count')
|
||||
->join('departments', 'patents.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name')
|
||||
->get();
|
||||
|
||||
$total = $data->sum('count');
|
||||
|
||||
return response()->json([
|
||||
'labels' => $data->pluck('department'),
|
||||
'values' => $data->pluck('count'),
|
||||
'total' => $total,
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsComparison(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
$departmentId = $request->query('department_id');
|
||||
if (empty($departmentId) && $user && $user->role_id == 2) {
|
||||
$departmentId = $user->department_id;
|
||||
}
|
||||
$year = $request->query('year');
|
||||
|
||||
$models = [
|
||||
'ActivitiesAttended' => ['class' => ActivitiesAttended::class, 'date_field' => 'end_date'],
|
||||
'ActivitiesOrganised' => ['class' => ActivitiesOrganised::class, 'date_field' => 'end_date'],
|
||||
'BooksPublished' => ['class' => BooksPublished::class, 'date_field' => 'date_of_publication'],
|
||||
'ExternalEngagement' => ['class' => ExternalEngagement::class, 'date_field' => 'end_date'],
|
||||
'IvOrganised' => ['class' => IvOrganised::class, 'date_field' => 'end_date'],
|
||||
'OnlineCourse' => ['class' => OnlineCourse::class, 'date_field' => 'end_date'],
|
||||
'Patent' => ['class' => Patent::class, 'date_field' => 'date_of_submission'],
|
||||
'Publication' => ['class' => Publication::class, 'date_field' => 'end_date'],
|
||||
];
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($models as $label => $modelConfig) {
|
||||
$query = $modelConfig['class']::query();
|
||||
if($departmentId) {
|
||||
$query->where('department_id', $departmentId);
|
||||
}
|
||||
if ($year && $year !== 'all') {
|
||||
$query->whereYear($modelConfig['date_field'], $year);
|
||||
}
|
||||
$count = $query->count();
|
||||
if ($count > 0) { // Only include data with non-zero count
|
||||
$data[] = [
|
||||
'label' => $label,
|
||||
'count' => $count,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$total = array_sum(array_column($data, 'count'));
|
||||
|
||||
return response()->json([
|
||||
'labels' => array_column($data, 'label'),
|
||||
'values' => array_column($data, 'count'),
|
||||
'total' => $total
|
||||
]);
|
||||
}
|
||||
|
||||
public function analyticsContribution(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
$model = $request->query('model', 'all');
|
||||
$year = $request->query('year');
|
||||
$departmentId = $request->query('department_id');
|
||||
if (empty($departmentId) && $user && $user->role_id == 2) {
|
||||
$departmentId = $user->department_id;
|
||||
}
|
||||
|
||||
$models = [
|
||||
'ActivitiesAttended' => ['class' => ActivitiesAttended::class, 'date_field' => 'end_date'],
|
||||
'ActivitiesOrganised' => ['class' => ActivitiesOrganised::class, 'date_field' => 'end_date'],
|
||||
'BooksPublished' => ['class' => BooksPublished::class, 'date_field' => 'date_of_publication'],
|
||||
'ExternalEngagement' => ['class' => ExternalEngagement::class, 'date_field' => 'end_date'],
|
||||
'IvOrganised' => ['class' => IvOrganised::class, 'date_field' => 'end_date'],
|
||||
'OnlineCourse' => ['class' => OnlineCourse::class, 'date_field' => 'end_date'],
|
||||
'Patent' => ['class' => Patent::class, 'date_field' => 'date_of_submission'],
|
||||
'Publication' => ['class' => Publication::class, 'date_field' => 'end_date'],
|
||||
];
|
||||
|
||||
$data = [];
|
||||
|
||||
if ($model === 'all') {
|
||||
$departments = Department::when($departmentId, function ($query) use ($departmentId) {
|
||||
return $query->where('id', $departmentId);
|
||||
})->get();
|
||||
|
||||
foreach ($departments as $department) {
|
||||
$count = 0;
|
||||
foreach ($models as $modelConfig) {
|
||||
$query = $modelConfig['class']::where('department_id', $department->id);
|
||||
if ($year && $year !== 'all') {
|
||||
$query->whereYear($modelConfig['date_field'], $year);
|
||||
}
|
||||
$count += $query->count();
|
||||
}
|
||||
if ($count > 0) { // Only include data with non-zero count
|
||||
$data[] = [
|
||||
'label' => $department->name,
|
||||
'count' => $count,
|
||||
];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$modelConfig = $models[$model];
|
||||
$modelClass = $modelConfig['class'];
|
||||
$table = (new $modelClass)->getTable();
|
||||
|
||||
$query = $modelClass::selectRaw('departments.name as label, COUNT(*) as count')
|
||||
->join('departments', $table . '.department_id', '=', 'departments.id')
|
||||
->groupBy('departments.name');
|
||||
|
||||
if ($year && $year !== 'all') {
|
||||
$query->whereYear($table . '.' . $modelConfig['date_field'], $year);
|
||||
}
|
||||
|
||||
if ($departmentId) {
|
||||
$query->where($table . '.department_id', $departmentId);
|
||||
}
|
||||
|
||||
$data = $query->get()->filter(function ($item) {
|
||||
return $item['count'] > 0; // Filter out data with zero count
|
||||
})->toArray();
|
||||
}
|
||||
|
||||
$total = array_sum(array_column($data, 'count'));
|
||||
|
||||
return response()->json([
|
||||
'labels' => array_column($data, 'label'),
|
||||
'values' => array_column($data, 'count'),
|
||||
'total' => $total
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,25 +201,39 @@ class PublicationsController extends Controller
|
||||
|
||||
if (!$user || !$user->scholar_url) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'No Google Scholar URL found for the logged-in user.'
|
||||
'error' => 'No Google Scholar URL found for the logged-in user.'
|
||||
], 400);
|
||||
}
|
||||
|
||||
$scholarService = new \App\Services\ScholarService();
|
||||
$publications = $scholarService->fetchPublications($user->scholar_url);
|
||||
$result = $scholarService->fetchPublications($user->scholar_url);
|
||||
|
||||
// If the service returned an error payload, forward it to UI
|
||||
if (is_array($result) && array_key_exists('error', $result)) {
|
||||
// Log more details if available
|
||||
if (isset($result['body'])) {
|
||||
\Log::error('ScholarService error body', ['body' => $result['body']]);
|
||||
} elseif (isset($result['raw'])) {
|
||||
\Log::warning('ScholarService returned empty articles', ['raw' => $result['raw']]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'error' => $result['error']
|
||||
], 200);
|
||||
}
|
||||
|
||||
// Expecting successful shape ['data' => [...]]
|
||||
$publications = $result['data'] ?? [];
|
||||
|
||||
if (empty($publications)) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'No publications found from the provided Scholar profile.'
|
||||
]);
|
||||
'error' => 'No publications found from the provided Scholar profile.'
|
||||
], 200);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'count' => count($publications),
|
||||
'data' => $publications,
|
||||
'count' => count($publications),
|
||||
]);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
|
||||
@@ -45,7 +45,7 @@ class UserController extends Controller
|
||||
->addColumn('role_name', function ($response) {
|
||||
$roles = [
|
||||
1 => 'Admin',
|
||||
2 => 'Coordinator',
|
||||
2 => 'HOD',
|
||||
3 => 'Faculty',
|
||||
];
|
||||
$options = '';
|
||||
|
||||
@@ -10,20 +10,22 @@ class ScholarService
|
||||
{
|
||||
try {
|
||||
// Extract Google Scholar profile ID (e.g., ssU-uBEAAAAJ)
|
||||
preg_match('/user=([^&]+)/', $url, $match);
|
||||
preg_match('/[?&]user=([^&]+)/', $url, $match);
|
||||
$profileId = $match[1] ?? null;
|
||||
|
||||
if (!$profileId) {
|
||||
\Log::warning('No Google Scholar ID found in URL: ' . $url);
|
||||
return [];
|
||||
$msg = 'No Google Scholar ID found in URL: ' . $url;
|
||||
\Log::warning($msg);
|
||||
return ['error' => $msg];
|
||||
}
|
||||
|
||||
// Load API key from .env
|
||||
$apiKey = env('SERPAPI_KEY');
|
||||
|
||||
if (!$apiKey) {
|
||||
\Log::error('SERPAPI_KEY not found in environment variables');
|
||||
return [];
|
||||
$msg = 'SERPAPI_KEY not found in environment variables';
|
||||
\Log::error($msg);
|
||||
return ['error' => $msg];
|
||||
}
|
||||
|
||||
$endpoint = 'https://serpapi.com/search.json';
|
||||
@@ -34,8 +36,10 @@ class ScholarService
|
||||
]);
|
||||
|
||||
if (!$response->successful()) {
|
||||
\Log::error('Scholar API request failed: ' . $response->status());
|
||||
return [];
|
||||
$status = $response->status();
|
||||
$body = $response->body();
|
||||
\Log::error('Scholar API request failed', ['status' => $status, 'body' => $body]);
|
||||
return ['error' => 'Scholar API request failed: ' . $status, 'body' => $body];
|
||||
}
|
||||
|
||||
$json = $response->json();
|
||||
@@ -46,8 +50,13 @@ class ScholarService
|
||||
?? $json['results']
|
||||
?? [];
|
||||
|
||||
if (empty($articles)) {
|
||||
\Log::warning('Scholar API returned no articles', ['profileId' => $profileId, 'response' => $json]);
|
||||
return ['error' => 'No publications returned by Scholar API', 'raw' => $json];
|
||||
}
|
||||
|
||||
// ✅ Format and return
|
||||
return collect($articles)
|
||||
$formatted = collect($articles)
|
||||
->map(function ($a) {
|
||||
return [
|
||||
'title' => $a['title'] ?? $a['name'] ?? null,
|
||||
@@ -59,6 +68,8 @@ class ScholarService
|
||||
})
|
||||
->toArray();
|
||||
|
||||
return ['data' => $formatted];
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
\Log::error('ScholarService API error: ' . $e->getMessage());
|
||||
return [];
|
||||
|
||||
Reference in New Issue
Block a user