Skip to content
Open
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
2 changes: 1 addition & 1 deletion app/config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"latte" => true,
"locale" => "tr_TR.utf8",
"timezone" => "Europe/Istanbul",
"mode" => "Production" #Development or Production
"mode" => "development" #Development or Production
];
4 changes: 3 additions & 1 deletion app/config/database.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@
"host" => "localhost",
"prefix" => "",
"user" => "root",
"password" => ""
"password" => "",
"cache" => false,
"cacheTime" => 60,
];
242 changes: 217 additions & 25 deletions app/controllers/Participate.php
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ public function apply()

$user = session_get("participator");
if ($survey->verifyPhone) {
if (Participator::checkSurveyIsParticipated($user->personalId, true))
warning("Bu anketi daha önce zaten cevapladınız!");
if (Participator::checkSurveyIsParticipated($surveyId, (string) $user->personalId, true))
warninglang("participate.already.answered");
}

$post = Request::post();
Expand All @@ -289,38 +289,98 @@ public function apply()


$formData = json_decode($survey->data);
foreach ($formData as $key => $value) {
if ($value->type == "description")
$slugToQuestion = [];
$slugToSection = [];
$sectionSlugs = [];
$activeSectionSlug = null;
foreach ($formData as $q) {
if (! isset($q->slug))
continue;
$slugToQuestion[$q->slug] = $q;
if ($q->type === "section") {
$activeSectionSlug = $q->slug;
$sectionSlugs[$q->slug] = true;
$slugToSection[$q->slug] = $q->slug;
continue;
}
$slugToSection[$q->slug] = $activeSectionSlug;
}

// Koşullu soru kontrolü - tüm soru tipleri için
$index = -1;
$hasCondition = false;

foreach ($formData as $dkey => $dvalue) {
// Eğer bu soru koşula sahipse
if (!empty($dvalue->conditions)) {
foreach ($dvalue->conditions as $i => $p) {
if ($p->value == $value->slug) {
$hasCondition = true; // Bu soru bir koşula bağlı
$parentAnswer = $post->{$dvalue->slug} ?? null;

if ($p->index == $parentAnswer) {
$index = $i;
break 2; // iki foreach'ten çık
}
}
$isConditionSatisfied = function ($parentQ, $cond) use ($post) {
if (! $parentQ || ! $cond)
return false;
$parentSlug = $parentQ->slug ?? "";
if ($parentSlug === "")
return false;
$expected = (string) ($cond->index ?? "");
if ($parentQ->type === "radio" || $parentQ->type === "select") {
$actual = isset($post->{$parentSlug}) ? (string) $post->{$parentSlug} : "";
return $actual !== "" && $actual === $expected;
}
if ($parentQ->type === "checkbox") {
$key = $parentSlug . $expected;
return isset($post->{$key});
}
return false;
};

$isSlugVisible = function ($slug) use ($formData, $slugToSection, $sectionSlugs, $isConditionSatisfied) {
if (! $slug)
return true;

$directRules = [];
foreach ($formData as $parentQ) {
if (empty($parentQ->conditions))
continue;
foreach ($parentQ->conditions as $cond) {
if (($cond->value ?? null) == $slug)
$directRules[] = [$parentQ, $cond];
}
}
if (! empty($directRules)) {
$ok = false;
foreach ($directRules as [$pQ, $cond]) {
if ($isConditionSatisfied($pQ, $cond)) {
$ok = true;
break;
}
}
if (! $ok)
return false;
}

// Eğer koşula bağlıysa ve koşul sağlanmamışsa bu soruyu atla
if ($hasCondition && $index == -1) {
continue;
$sectionSlug = $slugToSection[$slug] ?? null;
if (! $sectionSlug || ! isset($sectionSlugs[$sectionSlug]) || $sectionSlug === $slug)
return true;

$sectionRules = [];
foreach ($formData as $parentQ) {
if (empty($parentQ->conditions))
continue;
foreach ($parentQ->conditions as $cond) {
if (($cond->value ?? null) == $sectionSlug)
$sectionRules[] = [$parentQ, $cond];
}
}
if (empty($sectionRules))
return true;

foreach ($sectionRules as [$pQ, $cond]) {
if ($isConditionSatisfied($pQ, $cond))
return true;
}
return false;
};

foreach ($formData as $key => $value) {
if ($value->type == "description" || $value->type == "section")
continue;
if (! $isSlugVisible($value->slug))
continue;

switch ($value->type) {
case "radio":
case "sentiment_scale":
$rules[$value->slug] = [
"name" => $value->title,
#"required" => $value->isRequired,
Expand All @@ -344,7 +404,7 @@ public function apply()
$validate2 = ! in_array(true, $actions);

if ($validate2)
$errors[] = $value->title . " sorusunu cevaplayınız!";
$errors[] = lang("survey.validation.checkbox_required", strip_tags($value->title));
}

break;
Expand All @@ -360,6 +420,83 @@ public function apply()
$rules[$value->slug]["required"] = $value->isRequired;

break;

case "short_text":
$maxLen = isset($value->maxLength) ? (int) $value->maxLength : 255;
if ($maxLen < 1)
$maxLen = 255;
if ($maxLen > 4000)
$maxLen = 4000;
$rules[$value->slug] = [
"name" => $value->title . "<br>",
"max" => $maxLen,
];
if ($value->isRequired)
$rules[$value->slug]["required"] = true;
break;

case "email":
$rules[$value->slug] = [
"name" => $value->title . "<br>",
"max" => 255,
];
if ($value->isRequired)
$rules[$value->slug]["required"] = true;
break;

case "url":
$rules[$value->slug] = [
"name" => $value->title . "<br>",
"max" => 2048,
];
if ($value->isRequired)
$rules[$value->slug]["required"] = true;
break;

case "phone":
$rules[$value->slug] = [
"name" => $value->title . "<br>",
"max" => 32,
];
if ($value->isRequired)
$rules[$value->slug]["required"] = true;
break;

case "date":
case "time":
$rules[$value->slug] = [
"name" => $value->title . "<br>",
"max" => 32,
];
if ($value->isRequired)
$rules[$value->slug]["required"] = true;
break;

case "number":
$rules[$value->slug] = [
"name" => $value->title . "<br>",
];
if ($value->isRequired)
$rules[$value->slug]["required"] = true;
break;

case "select":
$rules[$value->slug] = [
"name" => $value->title . "<br>",
"min" => 0,
"max" => max(0, count($value->answers) - 1),
];
if ($value->isRequired)
$rules[$value->slug]["required"] = true;
break;

case "scale":
$rules[$value->slug] = [
"name" => $value->title . "<br>",
];
if ($value->isRequired)
$rules[$value->slug]["required"] = true;
break;
}
}

Expand All @@ -371,6 +508,61 @@ public function apply()
if ($validate)
warning($validate);

foreach ($formData as $value) {
if ($value->type === "description" || $value->type === "section")
continue;
if (! $isSlugVisible($value->slug))
continue;
$slug = $value->slug;
if ($value->type === "email") {
$raw = isset($post->$slug) ? trim((string) $post->$slug) : "";
if ($raw !== "" && ! validate_email($raw))
warning(lang("validation.email_error"));
}
if ($value->type === "url") {
$raw = isset($post->$slug) ? trim((string) $post->$slug) : "";
if ($raw !== "" && ! filter_var($raw, FILTER_VALIDATE_URL))
warning(lang("validation.url.error", strip_tags($value->title)));
}
if ($value->type === "phone") {
$raw = isset($post->$slug) ? trim((string) $post->$slug) : "";
if ($raw === "")
continue;
$digits = preg_replace('/\D+/', '', $raw);
if ($digits !== "" && strlen($digits) < 10)
warning(lang("validation.phone.error", strip_tags($value->title)));
}
if ($value->type === "number") {
$raw = isset($post->$slug) ? trim((string) $post->$slug) : "";
if ($raw === "")
continue;
if (! is_numeric($raw))
warning(lang("survey.validation.number_range", strip_tags($value->title)));
$num = 0 + $raw;
if (isset($value->numMin) && is_numeric($value->numMin) && $num < (float) $value->numMin)
warning(lang("survey.validation.number_range", strip_tags($value->title)));
if (isset($value->numMax) && is_numeric($value->numMax) && $num > (float) $value->numMax)
warning(lang("survey.validation.number_range", strip_tags($value->title)));
}
if ($value->type === "scale") {
$raw = isset($post->$slug) ? trim((string) $post->$slug) : "";
if ($raw === "")
continue;
if (! is_numeric($raw))
warning(lang("survey.validation.scale_range", strip_tags($value->title)));
$num = (float) $raw;
$smin = isset($value->scaleMin) ? (float) $value->scaleMin : 1;
$smax = isset($value->scaleMax) ? (float) $value->scaleMax : 5;
if ($smin > $smax) {
$t = $smin;
$smin = $smax;
$smax = $t;
}
if ($num < $smin || $num > $smax)
warning(lang("survey.validation.scale_range", strip_tags($value->title)));
}
}

$result = false;
if ($survey->verifyPhone) {
$result = $this->db->from("answers")
Expand Down
5 changes: 3 additions & 2 deletions app/controllers/Reports.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function watch(int $surveyId)
->from("personals")
->where("id", "!=", "0")
->where("status", "=", 1)
->orderBy("fullName", "ASC")
->orderBy("fullname", "ASC")
->results();

$args = [
Expand All @@ -54,7 +54,8 @@ public function watch(int $surveyId)
"anonymous" => $survey->anonymous,
"surveyId" => $surveyId,
"departmentList" => $departmentList,
"personList" => $personList
"personList" => $personList,
"reportEmptyLabel" => lang("survey.report.empty"),
];

if (!$survey->anonymous)
Expand Down
41 changes: 39 additions & 2 deletions app/controllers/surveys.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,37 @@

class Surveys extends Controller
{
/** Strings for public/js/app.js (survey builder). */
protected function surveyBuilderI18nJson(): string
{
$keys = [
'survey.builder.questions', 'survey.builder.create', 'survey.builder.developing', 'survey.builder.preview',
'survey.builder.required', 'survey.builder.horizontal_layout', 'survey.builder.condition_none', 'survey.builder.close',
'survey.builder.radio_list', 'survey.builder.checkbox_list', 'survey.builder.textarea', 'survey.builder.description',
'survey.builder.short_text', 'survey.builder.email', 'survey.builder.phone', 'survey.builder.url', 'survey.builder.date', 'survey.builder.time',
'survey.builder.number', 'survey.builder.select', 'survey.builder.scale',
'survey.builder.star_rating', 'survey.builder.like_dislike_scale', 'survey.builder.single_choice_scale',
'survey.builder.negative_label', 'survey.builder.positive_label', 'survey.builder.negative_value', 'survey.builder.positive_value',
'survey.builder.neutral_value', 'survey.builder.steps', 'survey.builder.unsectioned_zone',
'survey.builder.section', 'survey.builder.new_question', 'survey.builder.new_answer',
'survey.builder.desc_subtype.info', 'survey.builder.desc_subtype.warning', 'survey.builder.desc_subtype.success', 'survey.builder.desc_subtype.danger',
'survey.builder.max_length', 'survey.builder.min', 'survey.builder.max', 'survey.builder.step',
'survey.builder.scale_from', 'survey.builder.scale_to', 'survey.builder.label_left', 'survey.builder.label_right',
'survey.builder.cover_photo', 'survey.builder.upload_file', 'survey.builder.drag_drop', 'survey.builder.image_formats',
'survey.builder.about_survey', 'survey.builder.about_hint', 'survey.builder.cancel', 'survey.builder.save',
'survey.builder.anonymous_publish', 'survey.builder.apply_template', 'survey.builder.template_blank',
'survey.builder.template_satisfaction', 'survey.builder.template_contact',
'survey.builder.template_event_registration', 'survey.builder.template_customer_feedback', 'survey.builder.template_employee_pulse', 'survey.builder.template_lead_capture',
'survey.builder.draft_banner', 'survey.builder.section_subtitle',
'survey.builder.phone_placeholder', 'survey.builder.back', 'survey.builder.next', 'survey.builder.finish',
];
$out = [];
foreach ($keys as $k) {
$out[$k] = lang($k);
}
return json_encode($out, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS);
}

#[route(method: route::get | route::xhr_get, session: "user")]
public function index()
{
Expand All @@ -30,7 +61,10 @@ public function create()
"url" => "apply",
"surveyFormTitle" => lang("create.survey"),
"user" => User::info(),
"showIfOnEditMode" => false
"showIfOnEditMode" => false,
"surveyBuilderI18nJson" => $this->surveyBuilderI18nJson(),
"isSurveyEdit" => false,
"isSurveyCreateJs" => "true",
]);
}

Expand Down Expand Up @@ -178,7 +212,10 @@ public function edit(int $surveyId)
"user" => User::info(),
"surveyFormTitle" => $surveyFormTitle,
"url" => $isOnEditMode ? "apply/$surveyId" : "apply",
"showIfOnEditMode" => $isOnEditMode ? "<script>$(()=>{window.prepareSurveyForEditing(`$result`, `$data`)})</script>" : ""
"showIfOnEditMode" => $isOnEditMode ? "<script>$(()=>{window.prepareSurveyForEditing(`$result`, `$data`)})</script>" : "",
"surveyBuilderI18nJson" => $this->surveyBuilderI18nJson(),
"isSurveyEdit" => true,
"isSurveyCreateJs" => "false",
]);
}

Expand Down
Loading