get_answer_key_details()#
Belirtilen sınava ait cevap anahtarı detaylarını yetki kontrolü ile getiren güvenli fonksiyon.
Fonksiyon İmzası#
CREATE OR REPLACE FUNCTION get_answer_key_details(p_exam_id INTEGER)
RETURNS JSON
SECURITY DEFINER
SET search_path TO 'public'Amaç#
Bir sınava ait cevap anahtarını güvenli bir şekilde getirir. Öğretmenler sadece kendi sınıflarının sınavlarını, öğrenciler ise kayıtlı oldukları sınıfların sınavlarını görebilir.
Parametreler#
| Parametre | Tip | Açıklama |
|---|---|---|
p_exam_id | INTEGER | Cevap anahtarı istenilen sınavın ID’si |
Dönüş Değeri#
Type: JSON
Başarılı Yanıt:
{
"exam_id": 42,
"exam_title": "Matematik Vize Sınavı",
"class_id": 15,
"status": "active",
"system_status": "completed",
"answer_key": {
"1": "A",
"2": "C",
"3": "B"
},
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T14:20:00Z"
}Hata Kodları#
| SQLSTATE | Mesaj | Açıklama |
|---|---|---|
USER_NOT_FOUND | Oturum açmanız gerekiyor | Kullanıcı auth.uid() bulunamadı |
EXAM_NOT_FOUND | Sınav bulunamadı | Belirtilen ID’de sınav yok |
UNAUTHORIZED | Bu sınavı görüntüleme yetkiniz yok | Yetki kontrolü başarısız |
INVALID_ROLE | Geçersiz kullanıcı rolü | Role_id 1 veya 2 değil |
NO_ANSWER_KEY | Bu sınav için henüz cevap anahtarı yüklenmemiş | Answer_key NULL |
SQL Kodu#
CREATE OR REPLACE FUNCTION public.get_answer_key_details(p_exam_id integer)
RETURNS json
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO 'public'
AS $function$
DECLARE
v_user_id int;
v_user_role_id int;
v_exam_record record;
v_class_teacher_id int;
v_is_class_member boolean := false;
v_result json;
BEGIN
SELECT id, role_id
INTO v_user_id, v_user_role_id
FROM users
WHERE auth_user_id = auth.uid();
IF v_user_id IS NULL THEN
RAISE EXCEPTION 'Oturum açmanız gerekiyor.'
USING HINT = 'USER_NOT_FOUND';
END IF;
SELECT e.*, c.teacher_id
INTO v_exam_record
FROM exams e
INNER JOIN classes c ON e.class_id = c.id
WHERE e.id = p_exam_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'Sınav bulunamadı.'
USING HINT = 'EXAM_NOT_FOUND';
END IF;
v_class_teacher_id := v_exam_record.teacher_id;
IF v_user_role_id = 2 THEN
IF v_class_teacher_id != v_user_id THEN
RAISE EXCEPTION 'Bu sınavı görüntüleme yetkiniz yok.'
USING HINT = 'UNAUTHORIZED';
END IF;
ELSIF v_user_role_id = 1 THEN
SELECT EXISTS(
SELECT 1 FROM class_members
WHERE class_id = v_exam_record.class_id
AND student_id = v_user_id
AND deleted_at IS NULL
) INTO v_is_class_member;
IF NOT v_is_class_member THEN
RAISE EXCEPTION 'Bu sınavı görüntüleme yetkiniz yok.'
USING HINT = 'UNAUTHORIZED';
END IF;
ELSE
RAISE EXCEPTION 'Geçersiz kullanıcı rolü.'
USING HINT = 'INVALID_ROLE';
END IF;
IF v_exam_record.answer_key IS NULL THEN
RAISE EXCEPTION 'Bu sınav için henüz cevap anahtarı yüklenmemiş.'
USING HINT = 'NO_ANSWER_KEY';
END IF;
v_result := json_build_object(
'exam_id', v_exam_record.id,
'exam_title', v_exam_record.title,
'class_id', v_exam_record.class_id,
'status', v_exam_record.status,
'system_status', v_exam_record.system_status,
'answer_key', v_exam_record.answer_key,
'created_at', v_exam_record.created_at,
'updated_at', v_exam_record.updated_at
);
RETURN v_result;
EXCEPTION
WHEN OTHERS THEN
RAISE EXCEPTION '%', SQLERRM
USING HINT = SQLSTATE;
END;
$function$Kullanım Örneği#
Projede Kullanım#
Dosya: lib/common/services/api/exam_api.dart
Satır: ~217
Açıklama: Exam API servisinde sınav cevap anahtarını çekmek için kullanılır.
final response = await _supabase.rpc(
'get_answer_key_details',
params: {'p_exam_id': examId}
);SQL Örneği#
-- Öğretmen olarak kendi sınavının cevap anahtarını getir
SELECT get_answer_key_details(42);
-- Öğrenci olarak kayıtlı olduğu sınıfın sınavını getir
SELECT get_answer_key_details(42);
-- Hata durumu: Yetkisiz erişim
SELECT get_answer_key_details(999);
-- ERROR: Bu sınavı görüntüleme yetkiniz yokGüvenlik Özellikleri#
- SECURITY DEFINER: Fonksiyon owner yetkisiyle çalışır
- SET search_path: SQL injection koruması
- Row Level Security: Kullanıcı bazlı erişim kontrolü
- Role-based Access: Öğretmen/öğrenci ayrımı
- Soft Delete Check: deleted_at kontrolü
İlgili Tablolar#
public.examspublic.classespublic.userspublic.class_membersauth.users
Notlar#
Dikkat: Bu fonksiyon sadece cevap anahtarını döndürür. Öğrencilerin cevaplarıyla karşılaştırma yapmaz.
Güvenlik: SECURITY DEFINER kullanıldığı için, fonksiyon içindeki tüm kontroller kritik öneme sahiptir.