Compare commits
52 Commits
main
...
docker-version
| Author | SHA1 | Date | |
|---|---|---|---|
| 847b99ea7b | |||
| 70fd2469be | |||
| f3453783e2 | |||
| 69debeeffd | |||
| 266447e03d | |||
| 747043d616 | |||
| be9d6e3687 | |||
| 15abebe9ed | |||
| beaac25180 | |||
| b494d45ed8 | |||
| 41eaf7c6df | |||
| 6ddf932bea | |||
| 93c7f74356 | |||
| 7fc4683cb3 | |||
| 8be72acf26 | |||
| fc32aa6935 | |||
| c37373c083 | |||
| 0ab592ecbc | |||
| 41fa599cd3 | |||
| 7294890f06 | |||
| 0d6e449808 | |||
| 9409a4dbd9 | |||
| a46f286ce2 | |||
| bf016af07c | |||
| 61c7a77431 | |||
| 09e981f94b | |||
| 30dd0c5b8d | |||
| e2684ef05a | |||
| c478be2f3f | |||
| 84b9182937 | |||
| d381fdfbe1 | |||
| f860ce5e5c | |||
| 74d2e3e602 | |||
| 725fb50e03 | |||
| 3e10131f81 | |||
| 677da3892d | |||
| c62211f393 | |||
| 2ec15193a0 | |||
| 32119b6911 | |||
| c7b06c0cba | |||
| 7d108ca032 | |||
| 5283c8aac9 | |||
| df5a21efa7 | |||
| 63aa362100 | |||
| 5d6b9a2f48 | |||
| 700bfb2994 | |||
| c20b900e33 | |||
| 5c96b6b72e | |||
| 026ee3f85d | |||
| dace80dd79 | |||
| f23743adab | |||
| 944758a215 |
@@ -0,0 +1,3 @@
|
||||
RewriteEngine On
|
||||
RewriteCond %{HTTPS} off
|
||||
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
||||
@@ -1,4 +1,4 @@
|
||||
# GENERATED. YOU SHOULDN'T MODIFY OR DELETE THIS FILE.
|
||||
# Scribe uses this file to know when you change something manually in your docs.
|
||||
.scribe/intro.md=5ba4520f0a0f744a7aceda778b683bb0
|
||||
.scribe/intro.md=731671c57601ba874fec492fc1cf37ad
|
||||
.scribe/auth.md=9bee2b1ef8a238b2e58613fa636d5f39
|
||||
@@ -0,0 +1,94 @@
|
||||
## Autogenerated by Scribe. DO NOT MODIFY.
|
||||
|
||||
name: '🪙 Gold'
|
||||
description: ''
|
||||
endpoints:
|
||||
-
|
||||
httpMethods:
|
||||
- GET
|
||||
uri: api/gold-rates
|
||||
metadata:
|
||||
groupName: '🪙 Gold'
|
||||
groupDescription: ''
|
||||
subgroup: 'Fetch Rates'
|
||||
subgroupDescription: ''
|
||||
title: 'Get current gold rates.'
|
||||
description: ''
|
||||
authenticated: false
|
||||
custom: []
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
urlParameters: []
|
||||
cleanUrlParameters: []
|
||||
queryParameters: []
|
||||
cleanQueryParameters: []
|
||||
bodyParameters: []
|
||||
cleanBodyParameters: []
|
||||
fileParameters: []
|
||||
responses:
|
||||
-
|
||||
status: 200
|
||||
content: '{"Meta_Data":{"Minutes_Ago":-0.01,"Current_Date":"2025-09-15 17:13:46","Update_Date":"2025-09-15 17:13:46"},"Rates":{"GRA":{"Selling":4858.08,"Type":"Gold","Name":"GRAMALTIN","Change":0.26,"Buying":4857.61},"XU100":{"Selling":10931.75,"Type":"Gold","Name":"XU100","Change":5.4},"DBITCOIN":{"Selling":0,"Type":"Gold","Name":"DBITCOIN","Change":-0.87},"GUMUS":{"Selling":56.07,"Type":"Gold","Name":"GUMUS","Change":-0.12,"Buying":56.03},"BRENT":{"Selling":0,"Type":"Gold","Name":"BRENT","Change":0.99},"ONS":{"Buying":0,"Type":"Gold","Name":"ONS","Selling":0,"Change":0.45},"HAS":{"Buying":4833.32,"Type":"Gold","Name":"GRAMHASALTIN","Selling":4833.79,"Change":0.26},"CEYREKALTIN":{"Buying":7891.66,"Type":"Gold","Name":"CEYREKALTIN","Selling":8071.59,"Change":0.01},"YARIMALTIN":{"Buying":15734,"Type":"Gold","Name":"YARIMALTIN","Selling":16143.19,"Change":0.01},"TAMALTIN":{"Buying":31566.65,"Type":"Gold","Name":"TAMALTIN","Selling":32187.64,"Change":0.01},"CUMHURIYETALTINI":{"Buying":32651,"Type":"Gold","Name":"CUMHURIYETALTINI","Selling":33144,"Change":-0.13},"ATAALTIN":{"Buying":32553.11,"Type":"Gold","Name":"ATAALTIN","Selling":33372.46,"Change":0.01},"14AYARALTIN":{"Buying":2811.4,"Type":"Gold","Name":"14AYARALTIN","Selling":2813.95,"Change":0.01},"18AYARALTIN":{"Buying":3600.57,"Type":"Gold","Name":"18AYARALTIN","Selling":3603.83,"Change":0.01},"YIA":{"Buying":4498.25,"Type":"Gold","Name":"22AYARBILEZIK","Selling":4502.32,"Change":0.01},"IKIBUCUKALTIN":{"Buying":78916.62,"Type":"Gold","Name":"IKIBUCUKALTIN","Selling":80172.88,"Change":0.01},"BESLIALTIN":{"Buying":159806.16,"Type":"Gold","Name":"BESLIALTIN","Selling":162912.88,"Change":0.01},"GREMSEALTIN":{"Buying":78916.62,"Type":"Gold","Name":"GREMSEALTIN","Selling":80715.93,"Change":0.01},"RESATALTIN":{"Buying":32553.11,"Type":"Gold","Name":"RESATALTIN","Selling":33372.46,"Change":0.01},"HAMITALTIN":{"Buying":32553.11,"Type":"Gold","Name":"HAMITALTIN","Selling":33372.46,"Change":0.01},"GPL":{"Buying":1849.92,"Type":"Platinum","Name":"GRAMPLATIN","Selling":1854.44,"Change":-0.58},"PAL":{"Buying":1563.23,"Type":"Palladium","Name":"GRAMPALADYUM","Selling":1567.85,"Change":-1.93}}}'
|
||||
headers:
|
||||
cache-control: 'no-cache, private'
|
||||
content-type: application/json
|
||||
access-control-allow-origin: '*'
|
||||
description: null
|
||||
custom: []
|
||||
responseFields: []
|
||||
auth: []
|
||||
controller: null
|
||||
method: null
|
||||
route: null
|
||||
custom: []
|
||||
-
|
||||
httpMethods:
|
||||
- GET
|
||||
uri: 'api/gold-rates/{goldName}'
|
||||
metadata:
|
||||
groupName: '🪙 Gold'
|
||||
groupDescription: ''
|
||||
subgroup: 'Fetch Rates'
|
||||
subgroupDescription: ''
|
||||
title: 'Get gold rate by name.'
|
||||
description: ''
|
||||
authenticated: false
|
||||
custom: []
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
urlParameters:
|
||||
goldName:
|
||||
name: goldName
|
||||
description: ''
|
||||
required: true
|
||||
example: rerum
|
||||
type: string
|
||||
enumValues: []
|
||||
exampleWasSpecified: false
|
||||
nullable: false
|
||||
custom: []
|
||||
cleanUrlParameters:
|
||||
goldName: rerum
|
||||
queryParameters: []
|
||||
cleanQueryParameters: []
|
||||
bodyParameters: []
|
||||
cleanBodyParameters: []
|
||||
fileParameters: []
|
||||
responses:
|
||||
-
|
||||
status: 404
|
||||
content: '{"error":"Currency not found"}'
|
||||
headers:
|
||||
cache-control: 'no-cache, private'
|
||||
content-type: application/json
|
||||
access-control-allow-origin: '*'
|
||||
description: null
|
||||
custom: []
|
||||
responseFields: []
|
||||
auth: []
|
||||
controller: null
|
||||
method: null
|
||||
route: null
|
||||
custom: []
|
||||
@@ -0,0 +1,83 @@
|
||||
## Autogenerated by Scribe. DO NOT MODIFY.
|
||||
|
||||
name: Time
|
||||
description: ''
|
||||
endpoints:
|
||||
-
|
||||
httpMethods:
|
||||
- GET
|
||||
uri: api/server-time
|
||||
metadata:
|
||||
groupName: Time
|
||||
groupDescription: ''
|
||||
subgroup: 'Server Info'
|
||||
subgroupDescription: ''
|
||||
title: 'Get current server time.'
|
||||
description: ''
|
||||
authenticated: false
|
||||
custom: []
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
urlParameters: []
|
||||
cleanUrlParameters: []
|
||||
queryParameters: []
|
||||
cleanQueryParameters: []
|
||||
bodyParameters: []
|
||||
cleanBodyParameters: []
|
||||
fileParameters: []
|
||||
responses:
|
||||
-
|
||||
status: 200
|
||||
content: '{"server_time":"17:13:46"}'
|
||||
headers:
|
||||
cache-control: 'no-cache, private'
|
||||
content-type: application/json
|
||||
access-control-allow-origin: '*'
|
||||
description: null
|
||||
custom: []
|
||||
responseFields: []
|
||||
auth: []
|
||||
controller: null
|
||||
method: null
|
||||
route: null
|
||||
custom: []
|
||||
-
|
||||
httpMethods:
|
||||
- GET
|
||||
uri: api/server-date
|
||||
metadata:
|
||||
groupName: Time
|
||||
groupDescription: ''
|
||||
subgroup: 'Server Info'
|
||||
subgroupDescription: ''
|
||||
title: 'Get current server date.'
|
||||
description: ''
|
||||
authenticated: false
|
||||
custom: []
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
urlParameters: []
|
||||
cleanUrlParameters: []
|
||||
queryParameters: []
|
||||
cleanQueryParameters: []
|
||||
bodyParameters: []
|
||||
cleanBodyParameters: []
|
||||
fileParameters: []
|
||||
responses:
|
||||
-
|
||||
status: 200
|
||||
content: '{"server_date":"2025-09-15"}'
|
||||
headers:
|
||||
cache-control: 'no-cache, private'
|
||||
content-type: application/json
|
||||
access-control-allow-origin: '*'
|
||||
description: null
|
||||
custom: []
|
||||
responseFields: []
|
||||
auth: []
|
||||
controller: null
|
||||
method: null
|
||||
route: null
|
||||
custom: []
|
||||
@@ -0,0 +1,92 @@
|
||||
name: '🪙 Gold'
|
||||
description: ''
|
||||
endpoints:
|
||||
-
|
||||
httpMethods:
|
||||
- GET
|
||||
uri: api/gold-rates
|
||||
metadata:
|
||||
groupName: '🪙 Gold'
|
||||
groupDescription: ''
|
||||
subgroup: 'Fetch Rates'
|
||||
subgroupDescription: ''
|
||||
title: 'Get current gold rates.'
|
||||
description: ''
|
||||
authenticated: false
|
||||
custom: []
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
urlParameters: []
|
||||
cleanUrlParameters: []
|
||||
queryParameters: []
|
||||
cleanQueryParameters: []
|
||||
bodyParameters: []
|
||||
cleanBodyParameters: []
|
||||
fileParameters: []
|
||||
responses:
|
||||
-
|
||||
status: 200
|
||||
content: '{"Meta_Data":{"Minutes_Ago":-0.01,"Current_Date":"2025-09-15 17:13:46","Update_Date":"2025-09-15 17:13:46"},"Rates":{"GRA":{"Selling":4858.08,"Type":"Gold","Name":"GRAMALTIN","Change":0.26,"Buying":4857.61},"XU100":{"Selling":10931.75,"Type":"Gold","Name":"XU100","Change":5.4},"DBITCOIN":{"Selling":0,"Type":"Gold","Name":"DBITCOIN","Change":-0.87},"GUMUS":{"Selling":56.07,"Type":"Gold","Name":"GUMUS","Change":-0.12,"Buying":56.03},"BRENT":{"Selling":0,"Type":"Gold","Name":"BRENT","Change":0.99},"ONS":{"Buying":0,"Type":"Gold","Name":"ONS","Selling":0,"Change":0.45},"HAS":{"Buying":4833.32,"Type":"Gold","Name":"GRAMHASALTIN","Selling":4833.79,"Change":0.26},"CEYREKALTIN":{"Buying":7891.66,"Type":"Gold","Name":"CEYREKALTIN","Selling":8071.59,"Change":0.01},"YARIMALTIN":{"Buying":15734,"Type":"Gold","Name":"YARIMALTIN","Selling":16143.19,"Change":0.01},"TAMALTIN":{"Buying":31566.65,"Type":"Gold","Name":"TAMALTIN","Selling":32187.64,"Change":0.01},"CUMHURIYETALTINI":{"Buying":32651,"Type":"Gold","Name":"CUMHURIYETALTINI","Selling":33144,"Change":-0.13},"ATAALTIN":{"Buying":32553.11,"Type":"Gold","Name":"ATAALTIN","Selling":33372.46,"Change":0.01},"14AYARALTIN":{"Buying":2811.4,"Type":"Gold","Name":"14AYARALTIN","Selling":2813.95,"Change":0.01},"18AYARALTIN":{"Buying":3600.57,"Type":"Gold","Name":"18AYARALTIN","Selling":3603.83,"Change":0.01},"YIA":{"Buying":4498.25,"Type":"Gold","Name":"22AYARBILEZIK","Selling":4502.32,"Change":0.01},"IKIBUCUKALTIN":{"Buying":78916.62,"Type":"Gold","Name":"IKIBUCUKALTIN","Selling":80172.88,"Change":0.01},"BESLIALTIN":{"Buying":159806.16,"Type":"Gold","Name":"BESLIALTIN","Selling":162912.88,"Change":0.01},"GREMSEALTIN":{"Buying":78916.62,"Type":"Gold","Name":"GREMSEALTIN","Selling":80715.93,"Change":0.01},"RESATALTIN":{"Buying":32553.11,"Type":"Gold","Name":"RESATALTIN","Selling":33372.46,"Change":0.01},"HAMITALTIN":{"Buying":32553.11,"Type":"Gold","Name":"HAMITALTIN","Selling":33372.46,"Change":0.01},"GPL":{"Buying":1849.92,"Type":"Platinum","Name":"GRAMPLATIN","Selling":1854.44,"Change":-0.58},"PAL":{"Buying":1563.23,"Type":"Palladium","Name":"GRAMPALADYUM","Selling":1567.85,"Change":-1.93}}}'
|
||||
headers:
|
||||
cache-control: 'no-cache, private'
|
||||
content-type: application/json
|
||||
access-control-allow-origin: '*'
|
||||
description: null
|
||||
custom: []
|
||||
responseFields: []
|
||||
auth: []
|
||||
controller: null
|
||||
method: null
|
||||
route: null
|
||||
custom: []
|
||||
-
|
||||
httpMethods:
|
||||
- GET
|
||||
uri: 'api/gold-rates/{goldName}'
|
||||
metadata:
|
||||
groupName: '🪙 Gold'
|
||||
groupDescription: ''
|
||||
subgroup: 'Fetch Rates'
|
||||
subgroupDescription: ''
|
||||
title: 'Get gold rate by name.'
|
||||
description: ''
|
||||
authenticated: false
|
||||
custom: []
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
urlParameters:
|
||||
goldName:
|
||||
name: goldName
|
||||
description: ''
|
||||
required: true
|
||||
example: rerum
|
||||
type: string
|
||||
enumValues: []
|
||||
exampleWasSpecified: false
|
||||
nullable: false
|
||||
custom: []
|
||||
cleanUrlParameters:
|
||||
goldName: rerum
|
||||
queryParameters: []
|
||||
cleanQueryParameters: []
|
||||
bodyParameters: []
|
||||
cleanBodyParameters: []
|
||||
fileParameters: []
|
||||
responses:
|
||||
-
|
||||
status: 404
|
||||
content: '{"error":"Currency not found"}'
|
||||
headers:
|
||||
cache-control: 'no-cache, private'
|
||||
content-type: application/json
|
||||
access-control-allow-origin: '*'
|
||||
description: null
|
||||
custom: []
|
||||
responseFields: []
|
||||
auth: []
|
||||
controller: null
|
||||
method: null
|
||||
route: null
|
||||
custom: []
|
||||
@@ -0,0 +1,81 @@
|
||||
name: Time
|
||||
description: ''
|
||||
endpoints:
|
||||
-
|
||||
httpMethods:
|
||||
- GET
|
||||
uri: api/server-time
|
||||
metadata:
|
||||
groupName: Time
|
||||
groupDescription: ''
|
||||
subgroup: 'Server Info'
|
||||
subgroupDescription: ''
|
||||
title: 'Get current server time.'
|
||||
description: ''
|
||||
authenticated: false
|
||||
custom: []
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
urlParameters: []
|
||||
cleanUrlParameters: []
|
||||
queryParameters: []
|
||||
cleanQueryParameters: []
|
||||
bodyParameters: []
|
||||
cleanBodyParameters: []
|
||||
fileParameters: []
|
||||
responses:
|
||||
-
|
||||
status: 200
|
||||
content: '{"server_time":"17:13:46"}'
|
||||
headers:
|
||||
cache-control: 'no-cache, private'
|
||||
content-type: application/json
|
||||
access-control-allow-origin: '*'
|
||||
description: null
|
||||
custom: []
|
||||
responseFields: []
|
||||
auth: []
|
||||
controller: null
|
||||
method: null
|
||||
route: null
|
||||
custom: []
|
||||
-
|
||||
httpMethods:
|
||||
- GET
|
||||
uri: api/server-date
|
||||
metadata:
|
||||
groupName: Time
|
||||
groupDescription: ''
|
||||
subgroup: 'Server Info'
|
||||
subgroupDescription: ''
|
||||
title: 'Get current server date.'
|
||||
description: ''
|
||||
authenticated: false
|
||||
custom: []
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
Accept: application/json
|
||||
urlParameters: []
|
||||
cleanUrlParameters: []
|
||||
queryParameters: []
|
||||
cleanQueryParameters: []
|
||||
bodyParameters: []
|
||||
cleanBodyParameters: []
|
||||
fileParameters: []
|
||||
responses:
|
||||
-
|
||||
status: 200
|
||||
content: '{"server_date":"2025-09-15"}'
|
||||
headers:
|
||||
cache-control: 'no-cache, private'
|
||||
content-type: application/json
|
||||
access-control-allow-origin: '*'
|
||||
description: null
|
||||
custom: []
|
||||
responseFields: []
|
||||
auth: []
|
||||
controller: null
|
||||
method: null
|
||||
route: null
|
||||
custom: []
|
||||
@@ -3,7 +3,7 @@
|
||||
Daily Financial Data: Provides access to real-time financial data updated through the Truncgil API, allowing users to track the daily performance of currency exchange rates and cryptocurrencies.
|
||||
|
||||
<aside>
|
||||
<strong>Base URL</strong>: <code>http://localhost:8000</code>
|
||||
<strong>Base URL</strong>: <code>https://finance.truncgil.com</code>
|
||||
</aside>
|
||||
|
||||
This documentation aims to provide all the information you need to work with our API.
|
||||
|
||||
@@ -1,66 +1,81 @@
|
||||
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
|
||||
<img src="public/img/logo-light.svg" width="400" alt="Truncgil Finance Logo Light" style="background-color: #333; padding: 10px; border-radius: 5px;">
|
||||
</p>
|
||||
|
||||
## About Laravel
|
||||
# Truncgil Finance Application
|
||||
|
||||
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
|
||||
|
||||
- [Simple, fast routing engine](https://laravel.com/docs/routing).
|
||||
- [Powerful dependency injection container](https://laravel.com/docs/container).
|
||||
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
|
||||
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
|
||||
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
|
||||
- [Robust background job processing](https://laravel.com/docs/queues).
|
||||
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
|
||||
Bu proje, Truncgil bünyesinde geliştirilen Docker tabanlı bir Laravel finans uygulamasıdır. Proje; PHP 8.2-FPM, Nginx ve MySQL 8.0 servislerini içermektedir.
|
||||
|
||||
Laravel is accessible, powerful, and provides tools required for large, robust applications.
|
||||
## 🚀 Hızlı Başlangıç (Kurulum)
|
||||
|
||||
## Learning Laravel
|
||||
Projeyi yerel ortamınızda veya sunucunuzda çalıştırmak için aşağıdaki adımları izleyin:
|
||||
|
||||
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework.
|
||||
### 1. Depoyu Klonlayın
|
||||
```bash
|
||||
git clone https://git.truncgil.com/truncgit/finance.git
|
||||
cd finance
|
||||
```
|
||||
|
||||
You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch.
|
||||
### 2. Yapılandırma Dosyasını Hazırlayın
|
||||
`.env.example` dosyasını `.env` olarak kopyalayın ve gerekli düzenlemeleri yapın:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
> **Önemli:** Docker içerisinde çalışırken `DB_HOST=db` ve `DB_PORT=3306` (docker iç ağı için) olarak ayarlanmalıdır. Dışarıdan erişim için Docker 3308 portunu kullanmaktadır.
|
||||
|
||||
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
|
||||
### 3. Servisleri Başlatın
|
||||
Proje içerisinde bulunan `restart.sh` betiği, port çakışmalarını kontrol eder, eski konteynerleri temizler ve sistemi Docker Compose ile ayağa kaldırır:
|
||||
```bash
|
||||
chmod +x restart.sh
|
||||
./restart.sh
|
||||
```
|
||||
|
||||
## Laravel Sponsors
|
||||
### 4. Uygulamaya Erişin
|
||||
Servisler başarıyla başlatıldıktan sonra tarayıcınızdan şu adrese gidebilirsiniz:
|
||||
- **Uygulama:** [http://localhost:8089](http://localhost:8089)
|
||||
- **Veritabanı (Dış Erişim):** localhost:3308
|
||||
|
||||
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
|
||||
---
|
||||
|
||||
### Premium Partners
|
||||
## 🛠️ Nasıl Çalışır? (Mimari)
|
||||
|
||||
- **[Vehikl](https://vehikl.com/)**
|
||||
- **[Tighten Co.](https://tighten.co)**
|
||||
- **[WebReinvent](https://webreinvent.com/)**
|
||||
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
|
||||
- **[64 Robots](https://64robots.com)**
|
||||
- **[Curotec](https://www.curotec.com/services/technologies/laravel/)**
|
||||
- **[Cyber-Duck](https://cyber-duck.co.uk)**
|
||||
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
|
||||
- **[Jump24](https://jump24.co.uk)**
|
||||
- **[Redberry](https://redberry.international/laravel/)**
|
||||
- **[Active Logic](https://activelogic.com)**
|
||||
- **[byte5](https://byte5.de)**
|
||||
- **[OP.GG](https://op.gg)**
|
||||
Proje, modern konteynerleştirme standartlarına uygun olarak tasarlanmıştır:
|
||||
|
||||
## Contributing
|
||||
### Servis Yapısı
|
||||
- **app:** PHP 8.2-FPM üzerinde koşan Laravel uygulamasıdır. `dockerfile` içerisinde gerekli PHP eklentileri (pdo_mysql, bcmath, gd vb.) ve otomatik görevler (cron) yapılandırılmıştır.
|
||||
- **web:** Nginx (alpine) sunucusudur. Gelen istekleri karşılar ve PHP servisine yönlendirir.
|
||||
- **db:** MySQL 8.0 veritabanıdır. Veriler `db_data` volume'ü içerisinde kalıcı olarak saklanır.
|
||||
|
||||
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
|
||||
### Otomatik Görevler (Cron)
|
||||
`dockerfile` içerisinde tanımlanan cron yapısı ile Laravel'in `artisan run-all-fetchs` komutu her dakika otomatik olarak çalıştırılır. Bu, finansal verilerin güncel tutulmasını sağlar.
|
||||
|
||||
## Code of Conduct
|
||||
### API Dokümantasyonu
|
||||
Proje içerisinde **Scribe** kullanılmaktadır. `dockerfile` build aşamasında API dokümantasyonu otomatik olarak üretilir.
|
||||
|
||||
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
|
||||
---
|
||||
|
||||
## Security Vulnerabilities
|
||||
## 💻 Faydalı Komutlar
|
||||
|
||||
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
|
||||
Aşağıdaki komutları konteyner içerisinde çalıştırmak için `docker exec` kullanabilirsiniz:
|
||||
|
||||
## License
|
||||
**Migrasyonları Çalıştır:**
|
||||
```bash
|
||||
docker exec -it truncgil-finance-app php artisan migrate
|
||||
```
|
||||
|
||||
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||
**Verileri Seed Et:**
|
||||
```bash
|
||||
docker exec -it truncgil-finance-app php artisan db:seed
|
||||
```
|
||||
|
||||
**Logları Takip Et:**
|
||||
```bash
|
||||
docker compose -p finance logs -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notlar
|
||||
- Uygulama anahtarı (`APP_KEY`) ilk build sırasında otomatik olarak üretilir.
|
||||
- Port veya servis isimlerini değiştirmek isterseniz `docker-compose.yml` ve `restart.sh` dosyalarını güncelleyebilirsiniz.
|
||||
|
||||
@@ -6,6 +6,7 @@ use Illuminate\Console\Command;
|
||||
use App\Jobs\FetchCurrencyRates;
|
||||
use App\Jobs\FetchGoldRates;
|
||||
use App\Jobs\MergeCurrencyAndGoldRates;
|
||||
use App\Jobs\FetchCryptoCurrencyRates;
|
||||
|
||||
class RunAllFetchs extends Command
|
||||
{
|
||||
@@ -21,7 +22,7 @@ class RunAllFetchs extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
protected $description = 'This command runs all fetch jobs for currency and gold rates.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
@@ -37,6 +38,11 @@ class RunAllFetchs extends Command
|
||||
$duration = microtime(true) - $start;
|
||||
$results[] = ['FetchCurrencyRates', number_format($duration, 2)];
|
||||
|
||||
$start = microtime(true);
|
||||
FetchCryptoCurrencyRates::dispatchSync();
|
||||
$duration = microtime(true) - $start;
|
||||
$results[] = ['FetchCryptoCurrencyRates', number_format($duration, 2)];
|
||||
|
||||
$start = microtime(true);
|
||||
FetchGoldRates::dispatchSync();
|
||||
$duration = microtime(true) - $start;
|
||||
|
||||
@@ -6,6 +6,7 @@ use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
use App\Jobs\FetchCurrencyRates;
|
||||
use App\Jobs\FetchGoldRates;
|
||||
use App\Jobs\FetchCryptoCurrencyRates;
|
||||
use App\Jobs\MergeCurrencyAndGoldRates;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
@@ -22,6 +23,7 @@ class Kernel extends ConsoleKernel
|
||||
{
|
||||
$schedule->job(new FetchCurrencyRates())->everyMinute();
|
||||
$schedule->job(new FetchGoldRates())->everyMinute();
|
||||
$schedule->job(new FetchCryptoCurrencyRates())->everyMinute();
|
||||
$schedule->job(new MergeCurrencyAndGoldRates())->everyMinute();
|
||||
}
|
||||
|
||||
@@ -42,6 +44,8 @@ class Kernel extends ConsoleKernel
|
||||
$schedule = app(Schedule::class);
|
||||
$schedule->job(new FetchCurrencyRates())->everyMinute();
|
||||
$schedule->job(new FetchGoldRates())->everyMinute();
|
||||
$schedule->job(new FetchCryptoCurrencyRates())->everyMinute();
|
||||
|
||||
$schedule->job(new MergeCurrencyAndGoldRates())->everyMinute();
|
||||
|
||||
// Diğer job'larınızı buraya ekleyin
|
||||
|
||||
@@ -4,8 +4,11 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\FetchCurrencyRates;
|
||||
use App\Jobs\FetchGoldRates;
|
||||
use App\Jobs\FetchCryptoCurrencyRates;
|
||||
use App\Jobs\MergeCurrencyAndGoldRates;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
|
||||
/**
|
||||
* Class CurrencyController
|
||||
@@ -14,38 +17,77 @@ use Illuminate\Support\Facades\Storage;
|
||||
*/
|
||||
class CurrencyController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches all jobs to fetch currency and gold rates synchronously.
|
||||
* Synchronously fetch all currency, crypto and gold rates.
|
||||
* Rate limited to 2 requests per 30 seconds.
|
||||
* @group Cron Job
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function runAllFetchs()
|
||||
{
|
||||
FetchCurrencyRates::dispatchSync();
|
||||
FetchGoldRates::dispatchSync();
|
||||
MergeCurrencyAndGoldRates::dispatchSync();
|
||||
try {
|
||||
|
||||
FetchCurrencyRates::dispatchSync();
|
||||
FetchGoldRates::dispatchSync();
|
||||
FetchCryptoCurrencyRates::dispatchSync();
|
||||
MergeCurrencyAndGoldRates::dispatchSync();
|
||||
|
||||
return response()->json([
|
||||
'status' => 'success',
|
||||
'message' => 'All currency, crypto and gold rates have been successfully updated'
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => 'Kurlar güncellenirken bir hata oluştu: ' . $e->getMessage()
|
||||
], 429);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all gold and currency rates
|
||||
*
|
||||
* Get all currency, crypto and gold rates.
|
||||
* @group All Rates
|
||||
* @subgroup Fetch Rates
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getAllRates()
|
||||
{
|
||||
$jsonFile = 'merged/rates.json';
|
||||
|
||||
// JSON dosyasından oku
|
||||
$jsonFile = 'merged/rates.json';
|
||||
if (Storage::exists($jsonFile)) {
|
||||
return response()->json(
|
||||
json_decode(Storage::get($jsonFile), true)
|
||||
);
|
||||
$data = json_decode(Storage::get($jsonFile), true);
|
||||
$currentDate = now();
|
||||
$updateDate = isset($data['Update_Date']) ? \Carbon\Carbon::parse($data['Update_Date']) : null;
|
||||
|
||||
if ($updateDate) {
|
||||
$minutesAgo = round($currentDate->diffInMinutes($updateDate), 2);
|
||||
$metaData = [
|
||||
'Minutes_Ago' => $minutesAgo,
|
||||
'Current_Date' => $currentDate->toDateTimeString(),
|
||||
'Update_Date' => $updateDate->toDateTimeString(),
|
||||
];
|
||||
unset($data['Update_Date']);
|
||||
$data = [
|
||||
'Meta_Data' => $metaData,
|
||||
'Rates' => $data
|
||||
];
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(['error' => 'Veri bulunamadı'], 404);
|
||||
return response()->json(['error' => 'Data not found'], 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current currency rates
|
||||
*
|
||||
* Get current currency rates.
|
||||
* @group 💵 Currency
|
||||
* @subgroup Fetch Rates
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getCurrentRates()
|
||||
@@ -53,17 +95,35 @@ class CurrencyController extends Controller
|
||||
// JSON dosyasından oku
|
||||
$jsonFile = 'currency/today.json';
|
||||
if (Storage::exists($jsonFile)) {
|
||||
return response()->json(
|
||||
json_decode(Storage::get($jsonFile), true)
|
||||
);
|
||||
$data = json_decode(Storage::get($jsonFile), true);
|
||||
$currentDate = now(); // Şu anki tarih
|
||||
$updateDate = isset($data['Update_Date']) ? \Carbon\Carbon::parse($data['Update_Date']) : null;
|
||||
|
||||
if ($updateDate) {
|
||||
$minutesAgo = round($currentDate->diffInMinutes($updateDate), 2); // Kaç dakika önce alındığı
|
||||
$metaData = [ // Tarih bilgileri için alt dizi
|
||||
'Minutes_Ago' => $minutesAgo,
|
||||
'Current_Date' => $currentDate->toDateTimeString(),
|
||||
'Update_Date' => $updateDate->toDateTimeString(), // Update_Date burada kalacak
|
||||
];
|
||||
unset($data['Update_Date']); // Rates içerisindeki Update_Date elemanını kaldır
|
||||
$data = [
|
||||
'Meta_Data' => $metaData, // Tarih bilgileri alt dizisi
|
||||
'Rates' => $data, // Kur bilgileri alt dizisi
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
return response()->json(['error' => 'Veri bulunamadı'], 404);
|
||||
return response()->json(['error' => 'Data not found'], 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current gold rates
|
||||
*
|
||||
* Get current gold rates.
|
||||
* @group 🪙 Gold
|
||||
* @subgroup Fetch Rates
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getGoldRates()
|
||||
@@ -71,17 +131,70 @@ class CurrencyController extends Controller
|
||||
// JSON dosyasından oku
|
||||
$jsonFile = 'gold/today.json';
|
||||
if (Storage::exists($jsonFile)) {
|
||||
return response()->json(
|
||||
json_decode(Storage::get($jsonFile), true)
|
||||
);
|
||||
$data = json_decode(Storage::get($jsonFile), true);
|
||||
$currentDate = now(); // Şu anki tarih
|
||||
$updateDate = isset($data['Update_Date']) ? \Carbon\Carbon::parse($data['Update_Date']) : null;
|
||||
|
||||
if ($updateDate) {
|
||||
$minutesAgo = round($currentDate->diffInMinutes($updateDate), 2); // Kaç dakika önce alındığı
|
||||
$metaData = [ // Tarih bilgileri için alt dizi
|
||||
'Minutes_Ago' => $minutesAgo,
|
||||
'Current_Date' => $currentDate->toDateTimeString(),
|
||||
'Update_Date' => $updateDate->toDateTimeString(), // Update_Date burada kalacak
|
||||
];
|
||||
unset($data['Update_Date']); // Rates içerisindeki Update_Date elemanını kaldır
|
||||
$data = [
|
||||
'Meta_Data' => $metaData, // Tarih bilgileri alt dizisi
|
||||
'Rates' => $data, // Kur bilgileri alt dizisi
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
return response()->json(['error' => 'Veri bulunamadı'], 404);
|
||||
return response()->json(['error' => 'Data not found'], 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the currency rate by its name
|
||||
*
|
||||
* Get current crypto rates.
|
||||
* @group ₿ Crypto
|
||||
* @subgroup Fetch Rates
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getCryptoCurrencyRates()
|
||||
{
|
||||
$jsonFile = 'crypto/today.json';
|
||||
if (Storage::exists($jsonFile)) {
|
||||
$data = json_decode(Storage::get($jsonFile), true);
|
||||
$currentDate = now();
|
||||
$updateDate = isset($data['Update_Date']) ? \Carbon\Carbon::parse($data['Update_Date']) : null;
|
||||
|
||||
if ($updateDate) {
|
||||
$minutesAgo = round($currentDate->diffInMinutes($updateDate), 2);
|
||||
$metaData = [
|
||||
'Minutes_Ago' => $minutesAgo,
|
||||
'Current_Date' => $currentDate->toDateTimeString(),
|
||||
'Update_Date' => $updateDate->toDateTimeString(),
|
||||
];
|
||||
unset($data['Update_Date']);
|
||||
$data = [
|
||||
'Meta_Data' => $metaData,
|
||||
'Rates' => $data,
|
||||
];
|
||||
}
|
||||
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
return response()->json(['error' => 'Data not found'], 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get currency rate by name.
|
||||
* @group 💵 Currency
|
||||
* @subgroup Fetch Rates
|
||||
*
|
||||
* @param string $currencyName
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
@@ -101,8 +214,10 @@ class CurrencyController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the gold rate by its name
|
||||
*
|
||||
* Get gold rate by name.
|
||||
* @group 🪙 Gold
|
||||
* @subgroup Fetch Rates
|
||||
*
|
||||
* @param string $goldName
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
@@ -120,4 +235,26 @@ class CurrencyController extends Controller
|
||||
|
||||
return response()->json(['error' => 'Data not found'], 404);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get crypto rate by name.
|
||||
* @group ₿ Crypto
|
||||
* @subgroup Fetch Rates
|
||||
*
|
||||
* @param string $cryptoCurrencyName
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getCryptoCurrencyRateByName($cryptoCurrencyName)
|
||||
{
|
||||
$jsonFile = 'crypto/today.json';
|
||||
if (Storage::exists($jsonFile)) {
|
||||
$data = json_decode(Storage::get($jsonFile), true);
|
||||
if (isset($data[$cryptoCurrencyName])) {
|
||||
return response()->json([$cryptoCurrencyName => $data[$cryptoCurrencyName]]);
|
||||
}
|
||||
return response()->json(['error' => 'Cryptocurrency not found'], 404);
|
||||
}
|
||||
|
||||
return response()->json(['error' => 'Data not found'], 404);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @OA\Info(title="Time and Date API", version="1.0.0")
|
||||
*/
|
||||
class TimeDateController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get current server time.
|
||||
* @group Time
|
||||
* @subgroup Server Info
|
||||
*
|
||||
* @OA\Get(
|
||||
* path="/server-time",
|
||||
* summary="Get Server Time",
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Successful response",
|
||||
* @OA\JsonContent(
|
||||
* @OA\Property(property="server_time", type="string", example="14:30:00")
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getServerTime(): JsonResponse
|
||||
{
|
||||
return response()->json(['server_time' => date('H:i:s')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current server date.
|
||||
* @group Time
|
||||
* @subgroup Server Info
|
||||
*
|
||||
* @OA\Get(
|
||||
* path="/server-date",
|
||||
* summary="Get Server Date",
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="Successful response",
|
||||
* @OA\JsonContent(
|
||||
* @OA\Property(property="server_date", type="string", example="2023-10-01")
|
||||
* )
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function getServerDate(): JsonResponse
|
||||
{
|
||||
return response()->json(['server_date' => date('Y-m-d')]);
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ class Kernel extends HttpKernel
|
||||
'password.confirm' => \Illuminate\Auth\Middleware\EnsurePasswordIsConfirmed::class,
|
||||
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
|
||||
'api' => \App\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
'custom.throttle' => \App\Http\Middleware\CustomThrottleRequests::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Cache\RateLimiter;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class CustomThrottleRequests
|
||||
{
|
||||
protected $limiter;
|
||||
|
||||
public function __construct(RateLimiter $limiter)
|
||||
{
|
||||
$this->limiter = $limiter;
|
||||
}
|
||||
|
||||
public function handle(Request $request, Closure $next, $maxAttempts = 60, $decayMinutes = 1): Response
|
||||
{
|
||||
$key = $request->ip();
|
||||
|
||||
if ($this->limiter->tooManyAttempts($key, $maxAttempts)) {
|
||||
return response()->json([
|
||||
'error' => 'Rate limit aşıldı',
|
||||
'message' => 'Bu endpoint 30 dakikada bir kez çağrılabilir.',
|
||||
'retry_after' => $this->limiter->availableIn($key)
|
||||
], 429);
|
||||
}
|
||||
|
||||
$this->limiter->hit($key, $decayMinutes * 60);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Helpers\NumberFormatter;
|
||||
|
||||
class FetchCryptoCurrencyRates implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$data = [];
|
||||
$data['Update_Date'] = now()->format('Y-m-d H:i:s');
|
||||
|
||||
// Kripto para kurları
|
||||
$response = $this->fetchData('https://www.doviz.com/kripto-paralar');
|
||||
// DOM işlemleri için veri çekme
|
||||
$dom = new \DOMDocument();
|
||||
@$dom->loadHTML($response->body());
|
||||
$xpath = new \DOMXPath($dom);
|
||||
|
||||
// Kripto para verilerini içeren tabloyu ID'ye göre bul
|
||||
$rows = $xpath->query("//table[@id='coins']/tbody/tr");
|
||||
foreach ($rows as $row) {
|
||||
$symbol = trim($xpath->evaluate("string(.//td[1]//text()[last()])", $row));
|
||||
// Semboldeki boşlukları temizle ve sadece kripto para sembolünü al
|
||||
$symbol = preg_replace('/^.*\s(\w+)\s*$/', '$1', $symbol);
|
||||
|
||||
// Kripto para ismini al
|
||||
$name = $xpath->evaluate("string(.//td[1]//div[@class='cname'])", $row);
|
||||
|
||||
if (strlen($symbol) > 0) {
|
||||
$priceUSD = $xpath->evaluate("string(.//td[2])", $row);
|
||||
$priceTRY = $xpath->evaluate("string(.//td[3])", $row);
|
||||
$change = $xpath->evaluate("string(.//td[6])", $row);
|
||||
|
||||
// Fiyat verilerini temizle (örn: $3.310,57 -> 3310.57)
|
||||
$priceUSD = str_replace('$', '', $priceUSD);
|
||||
$priceUSD = str_replace('.', '', $priceUSD);
|
||||
$priceUSD = str_replace(',', '.', $priceUSD);
|
||||
|
||||
$priceTRY = str_replace('₺', '', $priceTRY);
|
||||
$priceTRY = str_replace('.', '', $priceTRY);
|
||||
$priceTRY = str_replace(',', '.', $priceTRY);
|
||||
|
||||
$change = str_replace('%', '', $change);
|
||||
$change = str_replace('.', '', $change);
|
||||
$change = str_replace(',', '.', $change);
|
||||
|
||||
$data[$symbol] = [
|
||||
'Name' => trim($name),
|
||||
'USD_Price' => (float)$priceUSD,
|
||||
'TRY_Price' => (float)$priceTRY,
|
||||
'Selling' => (float)$priceTRY,
|
||||
'Change' => (float)$change,
|
||||
'Type' => 'CryptoCurrency'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// JSON dosyasını kaydet
|
||||
Storage::put('crypto/today.json', json_encode($data, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function fetchData($url)
|
||||
{
|
||||
return Http::withHeaders([
|
||||
'User-Agent' => 'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10',
|
||||
'Accept-Language' => 'en'
|
||||
])->get($url);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ class FetchCurrencyRates implements ShouldQueue
|
||||
$data = [];
|
||||
$data['Update_Date'] = now()->format('Y-m-d H:i:s');
|
||||
|
||||
// Döviz kurları
|
||||
// Döviz kurları - ana kaynak
|
||||
$response = $this->fetchData('https://kur.doviz.com');
|
||||
|
||||
// DOM işlemleri için veri çekme
|
||||
@@ -38,19 +38,39 @@ class FetchCurrencyRates implements ShouldQueue
|
||||
if (trim($name) !== '') {
|
||||
if ($name == "JPY") $value = $value / 100;
|
||||
if (strlen($name) === 3) {
|
||||
// Para birimi ismini bul
|
||||
$nameElement = $xpath->query(".//div[@class='cname']", $element->parentNode);
|
||||
if ($nameElement->length > 0) {
|
||||
$data[$name]['Name'] = trim($nameElement->item(0)->nodeValue);
|
||||
}
|
||||
|
||||
if ($type == "bid") $data[$name]['Buying'] = (float)$value;
|
||||
if ($type == "ask") $data[$name]['Selling'] = (float)$value;
|
||||
if ($type == "c") $data[$name]['Change'] = round((float)$value, 2);
|
||||
|
||||
$data[$name]['Type'] = "Currency";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Eğer USD verisi yoksa veya boşsa, TCMB'den veri çek
|
||||
if (!isset($data['USD']) || empty($data['USD']['Buying'])) {
|
||||
\Log::info('USD verisi bulunamadı, TCMB\'den veri çekiliyor...');
|
||||
$tcmbData = $this->fetchFromTCMB();
|
||||
if (!empty($tcmbData)) {
|
||||
\Log::info('TCMB\'den ' . count($tcmbData) . ' kur alındı');
|
||||
$data = array_merge($data, $tcmbData);
|
||||
} else {
|
||||
\Log::error('TCMB\'den veri alınamadı');
|
||||
}
|
||||
}
|
||||
|
||||
// AZN kuru için
|
||||
$aznResponse = $this->fetchData('https://wise.com/tr/currency-converter/azn-to-try-rate?amount=1');
|
||||
preg_match('/(\d+\.\d+)\s+TRY/', $aznResponse->body(), $matches);
|
||||
if (isset($matches[1])) {
|
||||
$data['AZN'] = [
|
||||
'Name' => 'AZERBAYCAN YENİ MANATI',
|
||||
'Buying' => NumberFormatter::commaToDot($matches[1]),
|
||||
'Selling' => NumberFormatter::commaToDot($matches[1]),
|
||||
'Change' => "0.00",
|
||||
@@ -71,4 +91,84 @@ class FetchCurrencyRates implements ShouldQueue
|
||||
'Accept-Language' => 'en'
|
||||
])->get($url);
|
||||
}
|
||||
|
||||
private function fetchFromTCMB()
|
||||
{
|
||||
try {
|
||||
$response = $this->fetchData('https://www.tcmb.gov.tr/kurlar/today.xml');
|
||||
|
||||
if (!$response->successful()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$xml = simplexml_load_string($response->body());
|
||||
if (!$xml) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = [];
|
||||
|
||||
// Currency mapping - TCMB'deki isimleri kod olarak kullan
|
||||
$currencyMap = [
|
||||
'USD' => 'US DOLLAR',
|
||||
'EUR' => 'EURO',
|
||||
'GBP' => 'POUND STERLING',
|
||||
'CHF' => 'SWISS FRANK',
|
||||
'JPY' => 'JAPENESE YEN',
|
||||
'CAD' => 'CANADIAN DOLLAR',
|
||||
'AUD' => 'AUSTRALIAN DOLLAR',
|
||||
'SEK' => 'SWEDISH KRONA',
|
||||
'NOK' => 'NORWEGIAN KRONE',
|
||||
'DKK' => 'DANISH KRONE',
|
||||
'RUB' => 'RUSSIAN ROUBLE',
|
||||
'CNY' => 'CHINESE RENMINBI',
|
||||
'SAR' => 'SAUDI RIYAL',
|
||||
'KWD' => 'KUWAITI DINAR',
|
||||
'QAR' => 'QATARI RIAL',
|
||||
'AED' => 'UNITED ARAB EMIRATES DIRHAM',
|
||||
'PKR' => 'PAKISTANI RUPEE',
|
||||
'KRW' => 'SOUTH KOREAN WON',
|
||||
'AZN' => 'AZERBAIJANI NEW MANAT',
|
||||
'BGN' => 'BULGARIAN LEV',
|
||||
'RON' => 'NEW LEU'
|
||||
];
|
||||
|
||||
foreach ($xml->Currency as $currency) {
|
||||
$code = (string)$currency['CurrencyCode'];
|
||||
$unit = (float)$currency->Unit;
|
||||
$name = (string)$currency->CurrencyName;
|
||||
$buying = (float)$currency->BanknoteBuying;
|
||||
$selling = (float)$currency->BanknoteSelling;
|
||||
$forexBuying = (float)$currency->ForexBuying;
|
||||
$forexSelling = (float)$currency->ForexSelling;
|
||||
|
||||
// Birim düzeltmesi (100 yen = 1 birim gibi)
|
||||
if ($unit > 1) {
|
||||
$buying = $buying / $unit;
|
||||
$selling = $selling / $unit;
|
||||
$forexBuying = $forexBuying / $unit;
|
||||
$forexSelling = $forexSelling / $unit;
|
||||
}
|
||||
|
||||
// Forex kurları varsa onları kullan, yoksa banknot kurlarını kullan
|
||||
$finalBuying = $forexBuying > 0 ? $forexBuying : $buying;
|
||||
$finalSelling = $forexSelling > 0 ? $forexSelling : $selling;
|
||||
|
||||
if ($finalBuying > 0 && $finalSelling > 0) {
|
||||
$data[$code] = [
|
||||
'Name' => $name,
|
||||
'Buying' => round($finalBuying, 4),
|
||||
'Selling' => round($finalSelling, 4),
|
||||
'Change' => 0.00,
|
||||
'Type' => 'Currency'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Helpers\NumberFormatter;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class FetchGoldRates implements ShouldQueue
|
||||
{
|
||||
@@ -23,30 +24,59 @@ class FetchGoldRates implements ShouldQueue
|
||||
// Altın kurları
|
||||
$goldResponse = $this->fetchData('https://altin.doviz.com');
|
||||
|
||||
|
||||
$domGold = new \DOMDocument();
|
||||
@$domGold->loadHTML($goldResponse->body());
|
||||
|
||||
$xpathGold = new \DOMXPath($domGold);
|
||||
|
||||
// Daha spesifik bir sorgu ile sadece ihtiyacımız olan elementleri seçiyoruz
|
||||
$elementsGold = $xpathGold->query("//*[@data-socket-key]");
|
||||
|
||||
|
||||
// Debug için gelen data-socket-key değerlerini loglamak için
|
||||
$socketKeys = [];
|
||||
|
||||
foreach ($elementsGold as $element) {
|
||||
$attrGold = $element->getAttribute('data-socket-key');
|
||||
$typeGold = $element->getAttribute('data-socket-attr');
|
||||
$valueGold = NumberFormatter::commaToDot($element->nodeValue);
|
||||
|
||||
// Debug için data-socket-key değerlerini topluyoruz
|
||||
if (!in_array($attrGold, $socketKeys)) {
|
||||
$socketKeys[] = $attrGold;
|
||||
}
|
||||
|
||||
if (trim($attrGold) !== '') {
|
||||
|
||||
// Önce orijinal ismi tam olarak koruyalım
|
||||
$nameGold = strtoupper(str_replace("-", "", $attrGold));
|
||||
$fullNameGold = $nameGold;
|
||||
$nameGold = str_replace("14", "OD", $nameGold);
|
||||
$nameGold = str_replace("18", "OS", $nameGold);
|
||||
$nameGold = str_replace("22", "YI", $nameGold);
|
||||
|
||||
// Veri tipi belirlemeleri
|
||||
$metalType = "Gold"; // Varsayılan olarak altın
|
||||
|
||||
// Özel metaller için tür kontrolü
|
||||
if (strpos($nameGold, 'GRAMPALADYUM') !== false) {
|
||||
$metalType = "Palladium";
|
||||
} elseif (strpos($nameGold, 'GRAMPLATIN') !== false) {
|
||||
$metalType = "Platinum";
|
||||
} elseif (strpos($nameGold, 'GRAMGUMUS') !== false) {
|
||||
$metalType = "Silver";
|
||||
}
|
||||
|
||||
// Kısaltma işlemleri
|
||||
$nameGold = str_replace("14AYARBILEZIK", "ODB", $nameGold);
|
||||
$nameGold = str_replace("18AYARBILEZIK", "OSB", $nameGold);
|
||||
$nameGold = str_replace("22AYARBILEZIK", "YIA", $nameGold);
|
||||
$nameGold = str_replace("GRAMALTIN", "GRA", $nameGold);
|
||||
$nameGold = str_replace("GRAMPLATIN", "GPL", $nameGold);
|
||||
$nameGold = str_replace("GRAMHASALTIN", "HAS", $nameGold);
|
||||
$nameGold = strtoupper(substr($nameGold, 0, 3));
|
||||
$nameGold = str_replace("GRAMPALADYUM", "PAL", $nameGold);
|
||||
$nameGold = str_replace("GRAMGUMUS", "GUM", $nameGold);
|
||||
|
||||
// Eğer bir kısaltma yapıldıysa, ilk 3 karakteri al
|
||||
// Aksi takdirde orijinal değeri kullan
|
||||
if ($nameGold != $fullNameGold) {
|
||||
$nameGold = strtoupper(substr($nameGold, 0, 3));
|
||||
}
|
||||
|
||||
$except = ['USD', 'EUR', 'GBP', 'XU1', 'BIT'];
|
||||
if (in_array($nameGold, $except)) {
|
||||
@@ -56,12 +86,14 @@ class FetchGoldRates implements ShouldQueue
|
||||
if ($typeGold == "bid") $data[$nameGold]['Buying'] = (float)$valueGold;
|
||||
if ($typeGold == "ask") $data[$nameGold]['Selling'] = (float)$valueGold;
|
||||
if ($typeGold == "s") $data[$nameGold]['Selling'] = (float)$valueGold;
|
||||
if ($typeGold == "c") $data[$nameGold]['Change'] = round((float)$valueGold,
|
||||
2);
|
||||
$data[$nameGold]['Type'] = "Gold";
|
||||
if ($typeGold == "c") $data[$nameGold]['Change'] = round((float)$valueGold, 2);
|
||||
$data[$nameGold]['Type'] = $metalType;
|
||||
$data[$nameGold]['Name'] = $fullNameGold;
|
||||
}
|
||||
}
|
||||
|
||||
// Debug için socket key'leri loglayalım
|
||||
Log::info('Available data-socket-keys: ' . implode(', ', $socketKeys));
|
||||
|
||||
// JSON dosyasını kaydet
|
||||
Storage::put('gold/today.json', json_encode($data, JSON_UNESCAPED_UNICODE));
|
||||
@@ -72,8 +104,9 @@ class FetchGoldRates implements ShouldQueue
|
||||
private function fetchData($url)
|
||||
{
|
||||
return Http::withHeaders([
|
||||
'User-Agent' => 'Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10',
|
||||
'Accept-Language' => 'en'
|
||||
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||
'Accept-Language' => 'tr-TR,tr;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||
'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8'
|
||||
])->get($url);
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,10 @@ class MergeCurrencyAndGoldRates implements ShouldQueue
|
||||
{
|
||||
$currencyData = $this->getData('currency/today.json');
|
||||
$goldData = $this->getData('gold/today.json');
|
||||
$cryptoCurrencyData = $this->getData('crypto/today.json');
|
||||
|
||||
// Verileri birleştir
|
||||
$mergedData = array_merge($currencyData, $goldData);
|
||||
$mergedData = array_merge($currencyData, $goldData, $cryptoCurrencyData);
|
||||
|
||||
// Birleştirilmiş veriyi dışarıya aktar
|
||||
Storage::put('merged/rates.json', json_encode($mergedData, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
@@ -24,10 +24,7 @@ class RouteServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
|
||||
});
|
||||
|
||||
|
||||
$this->routes(function () {
|
||||
Route::middleware('api')
|
||||
->prefix('api')
|
||||
|
||||
@@ -8519,12 +8519,12 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^8.2"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ INTRO
|
||||
// For example, if your logo is in public/img:
|
||||
// - 'logo' => '../img/logo.png' // for `static` type (output folder is public/docs)
|
||||
// - 'logo' => 'img/logo.png' // for `laravel` type
|
||||
'logo' => false,
|
||||
'logo' => 'img/logo-light.svg',
|
||||
|
||||
// Customize the "Last updated" value displayed in the docs by specifying tokens and formats.
|
||||
// Examples:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"USD":{"Name":"US DOLLAR","Buying":39.6792,"Selling":39.7506,"Change":0,"Type":"Currency"},"AUD":{"Name":"AUSTRALIAN DOLLAR","Buying":25.967,"Selling":26.1363,"Change":0,"Type":"Currency"},"DKK":{"Name":"DANISH KRONE","Buying":6.2523,"Selling":6.2831,"Change":0,"Type":"Currency"},"EUR":{"Name":"EURO","Buying":46.7222,"Selling":46.8064,"Change":0,"Type":"Currency"},"GBP":{"Name":"POUND STERLING","Buying":54.1032,"Selling":54.3853,"Change":0,"Type":"Currency"},"CHF":{"Name":"SWISS FRANK","Buying":49.8917,"Selling":50.212,"Change":0,"Type":"Currency"},"SEK":{"Name":"SWEDISH KRONA","Buying":4.1341,"Selling":4.1769,"Change":0,"Type":"Currency"},"CAD":{"Name":"CANADIAN DOLLAR","Buying":29.1614,"Selling":29.293,"Change":0,"Type":"Currency"},"KWD":{"Name":"KUWAITI DINAR","Buying":129.2622,"Selling":130.9536,"Change":0,"Type":"Currency"},"NOK":{"Name":"NORWEGIAN KRONE","Buying":3.9292,"Selling":3.9556,"Change":0,"Type":"Currency"},"SAR":{"Name":"SAUDI RIYAL","Buying":10.5802,"Selling":10.5992,"Change":0,"Type":"Currency"},"JPY":{"Name":"JAPENESE YEN","Buying":0.2742,"Selling":0.276,"Change":0,"Type":"Currency"},"BGN":{"Name":"BULGARIAN LEV","Buying":23.7551,"Selling":24.0659,"Change":0,"Type":"Currency"},"RON":{"Name":"NEW LEU","Buying":9.183,"Selling":9.3032,"Change":0,"Type":"Currency"},"RUB":{"Name":"RUSSIAN ROUBLE","Buying":0.5007,"Selling":0.5073,"Change":0,"Type":"Currency"},"CNY":{"Name":"CHINESE RENMINBI","Buying":5.5081,"Selling":5.5802,"Change":0,"Type":"Currency"},"PKR":{"Name":"PAKISTANI RUPEE","Buying":0.139,"Selling":0.1408,"Change":0,"Type":"Currency"},"QAR":{"Name":"QATARI RIAL","Buying":10.8255,"Selling":10.9671,"Change":0,"Type":"Currency"},"KRW":{"Name":"SOUTH KOREAN WON","Buying":0.0289,"Selling":0.0293,"Change":0,"Type":"Currency"},"AZN":{"Name":"AZERBAIJANI NEW MANAT","Buying":23.2099,"Selling":23.5136,"Change":0,"Type":"Currency"},"AED":{"Name":"UNITED ARAB EMIRATES DIRHAM","Buying":10.7422,"Selling":10.8828,"Change":0,"Type":"Currency"}}
|
||||
@@ -0,0 +1,48 @@
|
||||
version: '3'
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: dockerfile
|
||||
image: truncgil-finance-app:latest
|
||||
container_name: truncgil-finance-app
|
||||
restart: always
|
||||
volumes:
|
||||
- .:/var/www
|
||||
networks:
|
||||
- app-network
|
||||
|
||||
web:
|
||||
image: nginx:alpine
|
||||
container_name: truncgil-finance-web
|
||||
restart: always
|
||||
ports:
|
||||
- "8089:80"
|
||||
volumes:
|
||||
- .:/var/www
|
||||
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
|
||||
networks:
|
||||
- app-network
|
||||
|
||||
db:
|
||||
image: mysql:8.0
|
||||
container_name: truncgil-finance-db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: truncgil_finance
|
||||
MYSQL_USER: truncgil_finance
|
||||
MYSQL_PASSWORD: "QWEFaca123++"
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
networks:
|
||||
- app-network
|
||||
ports:
|
||||
- "3308:3306"
|
||||
|
||||
networks:
|
||||
app-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
@@ -0,0 +1,73 @@
|
||||
# Laravel için PHP 8.2 resmi imajını kullanıyoruz
|
||||
FROM php:8.2-fpm
|
||||
|
||||
|
||||
# Çalışma dizinini belirleyelim
|
||||
WORKDIR /var/www
|
||||
|
||||
# Gerekli bağımlılıkları yükleyelim
|
||||
RUN apt-get update && apt-get install -y \
|
||||
git \
|
||||
unzip \
|
||||
curl \
|
||||
libpng-dev \
|
||||
libonig-dev \
|
||||
libxml2-dev \
|
||||
zip \
|
||||
cron \
|
||||
&& service cron start && \
|
||||
docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd \
|
||||
&& echo "* * * * * cd /var/www && php /var/www/artisan run-all-fetchs >> /dev/null 2>&1" >> /etc/cron.d/laravel-cron \
|
||||
&& chmod 0644 /etc/cron.d/laravel-cron \
|
||||
&& crontab /etc/cron.d/laravel-cron
|
||||
|
||||
# Composer'ı yükleyelim
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
|
||||
|
||||
# Laravel proje dosyalarını kopyalayalım
|
||||
COPY . .
|
||||
|
||||
|
||||
# Gerekli dizinleri oluşturma
|
||||
RUN mkdir -p /var/www/storage/app/private/scribe
|
||||
|
||||
# Start of Selection
|
||||
RUN set -x && \
|
||||
echo "Dosya izinleri ayarlanıyor..." && \
|
||||
chown -R www-data:www-data /var/www && \
|
||||
echo "chown komutu tamamlandı" && \
|
||||
find /var/www -type d -exec chmod 775 {} \; && \
|
||||
echo "Dizin izinleri ayarlandı" && \
|
||||
find /var/www -type f -exec chmod 664 {} \; && \
|
||||
echo "Dosya izinleri ayarlandı" && \
|
||||
chmod -R 775 /var/www/storage && \
|
||||
echo "Storage izinleri ayarlandı" && \
|
||||
chmod -R 775 /var/www/bootstrap/cache && \
|
||||
echo "Cache izinleri ayarlandı" && \
|
||||
chmod -R 775 /var/www/storage/framework/views && \
|
||||
echo "Views izinleri ayarlandı" && \
|
||||
chmod -R 775 /var/www/public && \
|
||||
echo "Public dizin izinleri ayarlandı"
|
||||
# Laravel uygulamasını başlatma ve loglama
|
||||
|
||||
RUN set -x && \
|
||||
# echo "Laravel kurulum komutları başlatılıyor..." && \
|
||||
# php artisan migrate && \
|
||||
# echo "Migrasyon tamamlandı" && \
|
||||
php artisan key:generate && \
|
||||
echo "Uygulama anahtarı oluşturuldu" && \
|
||||
php artisan config:cache && \
|
||||
echo "Konfigürasyon önbelleğe alındı" && \
|
||||
php artisan route:cache && \
|
||||
echo "Rotalar önbelleğe alındı" && \
|
||||
php artisan view:cache && \
|
||||
echo "Görünümler önbelleğe alındı" && \
|
||||
php artisan storage:link && \
|
||||
echo "Storage sembolik bağlantısı oluşturuldu" && \
|
||||
php artisan scribe:generate && \
|
||||
echo "API dokümantasyonu oluşturuldu" && \
|
||||
echo "Laravel uygulaması başarıyla başlatıldı.";
|
||||
|
||||
|
||||
RUN service cron start && \
|
||||
echo "Cron başlatıldı"
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,65 @@
|
||||
server {
|
||||
listen 80; # 88 yerine 80 kullanın
|
||||
server_name localhost;
|
||||
root /var/www/public;
|
||||
index index.php index.html;
|
||||
|
||||
# Keep-alive ve connection ayarları (bağlantı birikmesini önlemek için)
|
||||
keepalive_timeout 65;
|
||||
keepalive_requests 100;
|
||||
client_max_body_size 20M;
|
||||
client_body_timeout 60s;
|
||||
client_header_timeout 60s;
|
||||
send_timeout 60s;
|
||||
|
||||
# HTTPS için proxy headers
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Port $server_port;
|
||||
|
||||
# Güvenlik başlıkları
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
|
||||
# Ana location
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# PHP dosyaları için
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass app:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
|
||||
# HTTPS için ek parametreler
|
||||
fastcgi_param HTTPS on;
|
||||
fastcgi_param HTTP_X_FORWARDED_PROTO https;
|
||||
|
||||
# Timeout ayarları
|
||||
fastcgi_read_timeout 300;
|
||||
fastcgi_connect_timeout 60;
|
||||
fastcgi_send_timeout 300;
|
||||
|
||||
# FastCGI keep-alive ve buffer ayarları (bağlantı birikmesini önlemek için)
|
||||
fastcgi_keep_conn on;
|
||||
fastcgi_buffering on;
|
||||
fastcgi_buffer_size 4k;
|
||||
fastcgi_buffers 8 4k;
|
||||
fastcgi_busy_buffers_size 8k;
|
||||
|
||||
# Connection pool ayarları
|
||||
fastcgi_max_temp_file_size 0;
|
||||
}
|
||||
|
||||
# Gizli dosyaları engelle
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
|
||||
# Log dosyalarını engelle
|
||||
location ~ /\.log {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 0 B After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 877 968"><g clip-path="url(#a)"><circle cx="391" cy="391" r="390.5" stroke="#009846" transform="matrix(-1 0 0 1 416 -56)" /><circle cx="468" cy="468" r="467.5" stroke="#009846" opacity=".3" transform="matrix(-1 0 0 1 493 -133)"/><circle cx="558" cy="558" r="557.5" stroke="#009846" opacity=".1" transform="matrix(-1 0 0 1 583 -223)" /><g filter="url(#b)"> <ellipse cx="583" cy="229.5" fill="#009846" rx="583" ry="229.5" transform="matrix(-1 0 0 1 621 -9)" /></g><g filter="url(#c)"><ellipse cx="262" cy="184.5" fill="#fff" rx="262" ry="184.5" transform="matrix(-1 0 0 1 99 42)" /></g></g><defs><filter id="b" width="1614" height="907" x="-769" y="-233" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix" /><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" /><feGaussianBlur result="effect1_foregroundBlur_3089_39042" stdDeviation="112" /></filter><filter id="c" width="972" height="817" x="-649" y="-182" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix" /><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape" /><feGaussianBlur result="effect1_foregroundBlur_3089_39042" stdDeviation="112" /></filter><clipPath id="a"><path fill="#fff" d="M877 0H0v968h877z" /></clipPath></defs></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "Truncgil Finance API",
|
||||
"short_name": "Truncgil Finance",
|
||||
"theme_color": "#009846",
|
||||
"background_color": "#009846",
|
||||
"display": "browser",
|
||||
"orientation": "portrait",
|
||||
"scope": "https://finance.truncgil.com/",
|
||||
"start_url": "https://finance.truncgil.com/",
|
||||
"icons": [
|
||||
{
|
||||
"src": "img/icons/icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icons/icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icons/icon-128x128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icons/icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icons/icon-152x152.png",
|
||||
"sizes": "152x152",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icons/icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icons/icon-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "img/icons/icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
@if($rate)
|
||||
<div class="card">
|
||||
<div class="title">
|
||||
|
||||
<p class="title-text">
|
||||
|
||||
{{$currencyName}}
|
||||
</p>
|
||||
<p class="percent" style="color: {{ ($rate['Change'] ?? 0) > 0 ? 'green' : '#B9101E' }}">
|
||||
{{ $rate['Change'] ?? 0 }}%
|
||||
</p>
|
||||
@if(($rate['Change'] ?? 0) > 0)
|
||||
<svg width="20" height="20" fill="green" style="position: relative; top: -2px;" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg" transform="rotate(180)"> <path d="M384 576q0-26 19-45t45-19h896q26 0 45 19t19 45-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45z"></path> </svg>
|
||||
@else
|
||||
<svg width="20" height="20" fill="#B9101E" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> <path d="M384 576q0-26 19-45t45-19h896q26 0 45 19t19 45-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45z"></path> </svg>
|
||||
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
<div class="data">
|
||||
<p>
|
||||
|
||||
{{$rate['Selling'] ?? '0.00'}} ₺
|
||||
</p>
|
||||
|
||||
<div class="range">
|
||||
<div class="fill" style="background-color: {{ ($rate['Change'] ?? 0) > 0 ? 'green' : '#B9101E' }};">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@@ -1,21 +1,44 @@
|
||||
<!-- See https://github.com/stoplightio/elements/blob/main/docs/getting-started/elements/elements-options.md for config -->
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>{!! $metadata['title'] !!}</title>
|
||||
<!-- Embed elements Elements via Web Component -->
|
||||
<script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@stoplight/elements/styles.min.css">
|
||||
<script src="https://unpkg.com/@stoplight/elements@9.0.0/web-components.min.js"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/@stoplight/elements@9.0.0/styles.min.css">
|
||||
<style>
|
||||
body {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
elements-api {
|
||||
--elements-border-radius: 6px;
|
||||
}
|
||||
|
||||
.sl-inline img {
|
||||
width: 400px;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sl-prose p {
|
||||
font-size: var(--fs-paragraph);
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.sl-text-base {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
h4.sl-text-paragraph.sl-leading-snug.sl-font-prose.sl-font-semibold.sl-text-heading {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<elements-api
|
||||
@foreach($htmlAttributes as $attribute => $value)
|
||||
{{-- Attributes specified first override later ones --}}
|
||||
@@ -23,12 +46,23 @@
|
||||
@endforeach
|
||||
apiDescriptionUrl="{!! $metadata['openapi_spec_url'] !!}"
|
||||
router="hash"
|
||||
layout="sidebar"
|
||||
layout="responsive"
|
||||
appearance="auto"
|
||||
hideTryIt="{!! ($tryItOut['enabled'] ?? true) ? '' : 'true'!!}"
|
||||
@if(!empty($metadata['logo']))
|
||||
logo="{!! $metadata['logo'] !!}"
|
||||
@endif
|
||||
/>
|
||||
|
||||
<script>
|
||||
setTimeout(function() {
|
||||
const linkElement = document.querySelector('a.sl-flex.sl-items-center.sl-px-4.sl-py-3.sl-border-t');
|
||||
if (linkElement) {
|
||||
linkElement.href = "https://truncgil.com"; // Yeni URL'yi buraya ekleyin
|
||||
linkElement.innerHTML = '<img src="https://truncgil.com.tr/yatay.svg" width="100" alt="Truncgil Teknoloji">'; // Resim URL'sini ve alternatif metni buraya ekleyin
|
||||
}
|
||||
}, 1000); // 1 saniye gecikme
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Proje dizinine git
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Proje adını tanımlayalım
|
||||
PROJECT_NAME="finance"
|
||||
DB_PORT="3308"
|
||||
|
||||
echo "🚀 '$PROJECT_NAME' projesi kontrol ediliyor..."
|
||||
|
||||
# 1. Port çakışmasını kontrol et ve temizle
|
||||
echo "🔍 Port $DB_PORT kontrol ediliyor..."
|
||||
CONFLICTING_CONTAINER=$(docker ps -q --filter "publish=$DB_PORT")
|
||||
if [ ! -z "$CONFLICTING_CONTAINER" ]; then
|
||||
echo "⚠️ Port $DB_PORT, $(docker ps --filter "id=$CONFLICTING_CONTAINER" --format "{{.Names}}") tarafından kullanılıyor. Temizleniyor..."
|
||||
docker rm -f "$CONFLICTING_CONTAINER"
|
||||
fi
|
||||
|
||||
# 2. İsim çakışmalarını temizle
|
||||
echo "🧹 İsim çakışmaları temizleniyor..."
|
||||
docker rm -f truncgil-finance-app truncgil-finance-web truncgil-finance-db 2>/dev/null
|
||||
|
||||
# 3. Servisleri başlat
|
||||
echo "🆙 Servisler başlatılıyor..."
|
||||
docker compose -p "$PROJECT_NAME" up -d --remove-orphans
|
||||
|
||||
# Durumu göster
|
||||
echo "📊 Mevcut durum ($PROJECT_NAME):"
|
||||
docker compose -p "$PROJECT_NAME" ps
|
||||
|
||||
echo "✅ '$PROJECT_NAME' projesi başarıyla ayağa kaldırıldı!"
|
||||
@@ -3,14 +3,14 @@
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Controllers\CurrencyController;
|
||||
use App\Http\Controllers\TimeDateController;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| API Routes
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
//Route::get('/run-all-fetchs', [CurrencyController::class, 'runAllFetchs']);
|
||||
Route::get('/run-all-fetchs', [CurrencyController::class, 'runAllFetchs']);
|
||||
|
||||
Route::get('/today.json', [CurrencyController::class, 'getAllRates']);
|
||||
|
||||
@@ -18,4 +18,12 @@ Route::get('/currency-rates', [CurrencyController::class, 'getCurrentRates']);
|
||||
Route::get('/currency-rates/{currencyName}', [CurrencyController::class, 'getCurrencyRateByName']);
|
||||
|
||||
Route::get('/gold-rates', [CurrencyController::class, 'getGoldRates']);
|
||||
Route::get('/gold-rates/{goldName}', [CurrencyController::class, 'getGoldRateByName']);
|
||||
Route::get('/gold-rates/{goldName}', [CurrencyController::class, 'getGoldRateByName']);
|
||||
|
||||
Route::get('/crypto-currency-rates', [CurrencyController::class, 'getCryptoCurrencyRates']);
|
||||
Route::get('/crypto-currency-rates/{cryptoCurrencyName}', [CurrencyController::class, 'getCryptoCurrencyRateByName']);
|
||||
|
||||
|
||||
Route::get('/server-time', [TimeDateController::class, 'getServerTime']);
|
||||
Route::get('/server-date', [TimeDateController::class, 'getServerDate']);
|
||||
|
||||
|
||||