mirror of
https://code.castopod.org/adaures/castopod
synced 2025-05-23 18:42:01 +00:00
feat: add npm for js dependencies + move src/ files to root folder
- add node service in docker-compose.yml - update .devcontainer Dockerfile by adding node, npm and vim - init package.json for npm with tailwindcss, postcss, commitlint and commitizen as dev dependencies - update default layout main header and footer - replace CI's welcome_message.php with home.php listing all podcasts - add AUTHORS.md file - add docs folder in which to place castopod's technical documentation
This commit is contained in:
parent
3bf9420b59
commit
cbb83a6f30
@ -6,6 +6,11 @@ RUN apt-get update && apt-get install -y \
|
|||||||
|
|
||||||
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
COPY --from=composer /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
|
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y nodejs
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get upgrade -y && \
|
apt-get upgrade -y && \
|
||||||
apt-get install -y git
|
apt-get install -y git vim
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
"bmewburn.vscode-intelephense-client",
|
"bmewburn.vscode-intelephense-client",
|
||||||
"streetsidesoftware.code-spell-checker",
|
"streetsidesoftware.code-spell-checker",
|
||||||
"naumovs.color-highlight",
|
"naumovs.color-highlight",
|
||||||
"heybourn.headwind"
|
"heybourn.headwind",
|
||||||
|
"anish-m.ci-snippets2",
|
||||||
|
"wayou.vscode-todo-highlight"
|
||||||
]
|
]
|
||||||
}
|
}
|
137
.gitignore
vendored
137
.gitignore
vendored
@ -1,3 +1,140 @@
|
|||||||
|
#-------------------------
|
||||||
|
# Operating Specific Junk Files
|
||||||
|
#-------------------------
|
||||||
|
|
||||||
|
# OS X
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# OS X Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Windows image file caches
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
*~
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
#-------------------------
|
||||||
|
# Environment Files
|
||||||
|
#-------------------------
|
||||||
|
# These should never be under version control,
|
||||||
|
# as it poses a security risk.
|
||||||
|
.env
|
||||||
|
.vagrant
|
||||||
|
Vagrantfile
|
||||||
|
|
||||||
|
#-------------------------
|
||||||
|
# Temporary Files
|
||||||
|
#-------------------------
|
||||||
|
writable/cache/*
|
||||||
|
!writable/cache/index.html
|
||||||
|
|
||||||
|
writable/logs/*
|
||||||
|
!writable/logs/index.html
|
||||||
|
|
||||||
|
writable/session/*
|
||||||
|
!writable/session/index.html
|
||||||
|
|
||||||
|
writable/uploads/*
|
||||||
|
!writable/uploads/index.html
|
||||||
|
|
||||||
|
writable/debugbar/*
|
||||||
|
|
||||||
|
php_errors.log
|
||||||
|
|
||||||
|
#-------------------------
|
||||||
|
# User Guide Temp Files
|
||||||
|
#-------------------------
|
||||||
|
user_guide_src/build/*
|
||||||
|
user_guide_src/cilexer/build/*
|
||||||
|
user_guide_src/cilexer/dist/*
|
||||||
|
user_guide_src/cilexer/pycilexer.egg-info/*
|
||||||
|
|
||||||
|
#-------------------------
|
||||||
|
# Test Files
|
||||||
|
#-------------------------
|
||||||
|
tests/coverage*
|
||||||
|
|
||||||
|
# Don't save phpunit under version control.
|
||||||
|
phpunit
|
||||||
|
|
||||||
|
#-------------------------
|
||||||
|
# Composer
|
||||||
|
#-------------------------
|
||||||
|
vendor
|
||||||
|
|
||||||
|
#-------------------------
|
||||||
|
# IDE / Development Files
|
||||||
|
#-------------------------
|
||||||
|
|
||||||
|
# Modules Testing
|
||||||
|
_modules/*
|
||||||
|
|
||||||
|
# phpenv local config
|
||||||
|
.php-version
|
||||||
|
|
||||||
|
# Jetbrains editors (PHPStorm, etc)
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# Netbeans
|
||||||
|
nbproject/
|
||||||
|
build/
|
||||||
|
nbbuild/
|
||||||
|
dist/
|
||||||
|
nbdist/
|
||||||
|
nbactions.xml
|
||||||
|
nb-configuration.xml
|
||||||
|
.nb-gradle/
|
||||||
|
|
||||||
|
# Sublime Text
|
||||||
|
*.tmlanguage.cache
|
||||||
|
*.tmPreferences.cache
|
||||||
|
*.stTheme.cache
|
||||||
|
*.sublime-workspace
|
||||||
|
*.sublime-project
|
||||||
|
.phpintel
|
||||||
|
/api/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
/results/
|
||||||
|
/phpunit*.xml
|
||||||
|
/.phpunit.*.cache
|
||||||
|
|
||||||
|
# Media files
|
||||||
|
public/media/*
|
||||||
|
|
||||||
|
# npm
|
||||||
|
yarn.lock
|
||||||
|
node_modules
|
||||||
|
|
||||||
|
# potcss generated file
|
||||||
|
public/index.css
|
||||||
|
|
||||||
#-------------------------
|
#-------------------------
|
||||||
# Docker volumes
|
# Docker volumes
|
||||||
#-------------------------
|
#-------------------------
|
||||||
|
4
AUTHORS.md
Normal file
4
AUTHORS.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Authors
|
||||||
|
|
||||||
|
[Benjamin Bellamy](https://code.podlibre.org/benjamin) <benjamin@podlibre.org>
|
||||||
|
[Yassine Doghri](https://code.podlibre.org/yassine) <yassine@podlibre.org>
|
@ -1,6 +1,6 @@
|
|||||||
FROM php:latest
|
FROM php:latest
|
||||||
|
|
||||||
COPY ./src /castopod
|
COPY . /castopod
|
||||||
WORKDIR /castopod
|
WORKDIR /castopod
|
||||||
|
|
||||||
### Install CodeIgniter's server requirements
|
### Install CodeIgniter's server requirements
|
||||||
|
149
README.md
149
README.md
@ -19,151 +19,6 @@ Moreover Podcasters can choose to publish on Castopod while keeping their existi
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Setup your development environment
|
## Documentation
|
||||||
|
|
||||||
Castopod is a web app based on the `php` framework [CodeIgniter 4](https://codeigniter.com).
|
You can check castopod's documentation for [setting up a development environment](./docs/setup-development.md).
|
||||||
|
|
||||||
To setup a dev environment, we use [Docker](https://www.docker.com/). A `docker-compose.yml` and `Dockerfile` are included in the project's root folder to help you kickstart your contribution.
|
|
||||||
|
|
||||||
> Know that you don't need any prior knowledge of Docker to follow the next steps. However, if you wish to use your own environment, feel free to do so!
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
0. Install [docker desktop](https://www.docker.com/products/docker-desktop).
|
|
||||||
|
|
||||||
1. Clone castopod project by running:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://code.podlibre.org/podlibre/castopod.git
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Create a `./src/.env` file with the minimum required config to connect the app to the database:
|
|
||||||
|
|
||||||
```env
|
|
||||||
CI_ENVIRONMENT = development
|
|
||||||
|
|
||||||
database.default.hostname = mariadb
|
|
||||||
database.default.database = castopod
|
|
||||||
database.default.username = podlibre
|
|
||||||
database.default.password = castopod
|
|
||||||
```
|
|
||||||
|
|
||||||
> _NB._ You can tweak your environment by setting more environment variables. See the `./src/env` for examples or the [CodeIgniter4 User Guide](https://codeigniter.com/user_guide/index.html) for more info.
|
|
||||||
|
|
||||||
3. Add the repository you've cloned to docker desktop's `Settings` > `Resources` > `File Sharing`.
|
|
||||||
4. Install castopod's php dependencies
|
|
||||||
- The project's dependencies aren't included in the repository, you have to download them using the composer service defined in `docker-compose.yml`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose run --rm composer install --ignore-platform-reqs
|
|
||||||
```
|
|
||||||
|
|
||||||
### Start docker containers
|
|
||||||
|
|
||||||
Go to project's root folder and run:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# starts all services declared in docker-compose.yml file
|
|
||||||
# -d option starts the containers in the background
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
# See all running processes (you should see 3 processes running)
|
|
||||||
docker ps
|
|
||||||
|
|
||||||
# Alternatively, you can check all processes (you should see composer with an Exited status)
|
|
||||||
docker ps -a
|
|
||||||
```
|
|
||||||
|
|
||||||
> The `docker-compose up -d` command will boot 3 containers in the background:
|
|
||||||
>
|
|
||||||
> - `castopod_app`: a php based container with codeigniter requirements installed
|
|
||||||
> - `castopod_mariadb`: a [mariadb](https://mariadb.org/) server for persistent data
|
|
||||||
> - `castopod_phpmyadmin`: a phpmyadmin server to visualize the mariadb database
|
|
||||||
>
|
|
||||||
> _NB._ `./mariadb`, `./phpmyadmin` folders will be mounted in the project's root directory to persist data and logs.
|
|
||||||
|
|
||||||
|
|
||||||
### Initialize and populate database
|
|
||||||
|
|
||||||
Build the database with the migrate command:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# loads the database schema during first migration
|
|
||||||
docker-compose run --rm app php spark migrate
|
|
||||||
```
|
|
||||||
|
|
||||||
Populate the database with the required data:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Populates all categories
|
|
||||||
docker-compose run --rm app php spark db:seed CategorySeeder
|
|
||||||
docker-compose run --rm app php spark db:seed LanguageSeeder
|
|
||||||
```
|
|
||||||
|
|
||||||
### Start hacking
|
|
||||||
|
|
||||||
You're all set! Start working your magic by updating the project's files! Help yourself to the [CodeIgniter4 User Guide](https://codeigniter.com/user_guide/index.html) for more insights.
|
|
||||||
|
|
||||||
To see your changes, go to:
|
|
||||||
|
|
||||||
- [localhost:8080](http://localhost:8080/) for the castopod app
|
|
||||||
- [localhost:8888](http://localhost:8888/) for the phpmyadmin interface:
|
|
||||||
|
|
||||||
- **Username**: podlibre
|
|
||||||
- **Password**: castopod
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Going Further during development
|
|
||||||
|
|
||||||
#### Update app dependencies
|
|
||||||
|
|
||||||
You can update the project's dependencies using the `composer` service:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose run --rm composer update --ignore-platform-reqs
|
|
||||||
```
|
|
||||||
|
|
||||||
> _NB._ Composer commands look for the `composer.json` file to find castopod's php dependencies, all of which live in the `./src/vendor` folder. For more info, check out [Composer documentation](https://getcomposer.org/doc/).
|
|
||||||
|
|
||||||
#### Useful docker / docker-compose commands
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# monitor the app container
|
|
||||||
docker logs --tail 50 --follow --timestamps castopod_app
|
|
||||||
|
|
||||||
# monitor the mariadb container
|
|
||||||
docker logs --tail 50 --follow --timestamps castopod_mariadb
|
|
||||||
|
|
||||||
# monitor the phpmyadmin container
|
|
||||||
docker logs --tail 50 --follow --timestamps castopod_phpmyadmin
|
|
||||||
|
|
||||||
# restart docker containers
|
|
||||||
docker-compose restart
|
|
||||||
|
|
||||||
# Destroy all containers, opposite of `up` command
|
|
||||||
docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
Check [docker](https://docs.docker.com/engine/reference/commandline/docker/) and [docker-compose](https://docs.docker.com/compose/reference/) documentations for more insights.
|
|
||||||
|
|
||||||
### Developing inside a Container
|
|
||||||
|
|
||||||
If you're working in VSCode, you can take advantage of the `./.devcontainer/` folder. It defines a development container with preinstalled VSCode extensions so you don't have to worry about them. The container will be loaded with php, composer and git:
|
|
||||||
|
|
||||||
1. Install the VSCode extension [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
|
||||||
2. `Ctrl/Cmd + Shift + P` > `Open in container`
|
|
||||||
|
|
||||||
The VSCode window will reload inside the dev container.
|
|
||||||
|
|
||||||
You can check that the required packages are running in the console (`Terminal` > `New Terminal`):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
php -v
|
|
||||||
|
|
||||||
composer -V
|
|
||||||
|
|
||||||
git version
|
|
||||||
```
|
|
||||||
|
|
||||||
For more info, see [VSCode Remote Containers](https://code.visualstudio.com/docs/remote/containers)
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
<?php namespace Config;
|
<?php
|
||||||
|
|
||||||
|
namespace Config;
|
||||||
|
|
||||||
use CodeIgniter\Config\BaseConfig;
|
use CodeIgniter\Config\BaseConfig;
|
||||||
|
|
||||||
@ -76,7 +78,7 @@ class App extends BaseConfig
|
|||||||
| If false, no automatic detection will be performed.
|
| If false, no automatic detection will be performed.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
public $negotiateLocale = false;
|
public $negotiateLocale = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
19
app/Controllers/Home.php
Normal file
19
app/Controllers/Home.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controllers;
|
||||||
|
|
||||||
|
use App\Models\PodcastModel;
|
||||||
|
|
||||||
|
class Home extends BaseController
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$model = new PodcastModel();
|
||||||
|
$data = ["podcasts" => $model->findAll()];
|
||||||
|
|
||||||
|
return view('home', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
}
|
@ -8,5 +8,6 @@ class Language extends Entity
|
|||||||
{
|
{
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'code' => 'string',
|
'code' => 'string',
|
||||||
|
'native_name' => 'string'
|
||||||
];
|
];
|
||||||
}
|
}
|
3
app/Javascript/assets/styles/index.css
Normal file
3
app/Javascript/assets/styles/index.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@import "tailwindcss/base";
|
||||||
|
@import "tailwindcss/components";
|
||||||
|
@import "tailwindcss/utilities";
|
6
app/Language/en/Home.php
Normal file
6
app/Language/en/Home.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?
|
||||||
|
|
||||||
|
return [
|
||||||
|
"all_podcasts" => "All podcasts",
|
||||||
|
"no_podcast" => "No podcast found"
|
||||||
|
];
|
141
app/Language/en/Podcasts.php
Normal file
141
app/Language/en/Podcasts.php
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<?
|
||||||
|
|
||||||
|
return [
|
||||||
|
"create" => "Create a Podcast",
|
||||||
|
"form" => [
|
||||||
|
'title' => 'Title',
|
||||||
|
'name' => 'Name',
|
||||||
|
'description' => 'Description',
|
||||||
|
'episode_description_footer' => 'Episode description footer',
|
||||||
|
'image' => 'Image',
|
||||||
|
'language' => 'Language',
|
||||||
|
'category' => 'Category',
|
||||||
|
'explicit' => 'Explicit',
|
||||||
|
'author' => 'Author',
|
||||||
|
'owner_name' => 'Owner name',
|
||||||
|
'owner_email' => 'Owner email',
|
||||||
|
'type' => [
|
||||||
|
'label' => 'Type',
|
||||||
|
'episodic' => 'Episodic',
|
||||||
|
'serial' => 'Serial',
|
||||||
|
],
|
||||||
|
'copyright' => 'Copyright',
|
||||||
|
'block' => 'Block',
|
||||||
|
'complete' => 'Complete',
|
||||||
|
'custom_html_head' => 'Custom HTML code in <head/>',
|
||||||
|
'submit' => 'Create podcast',
|
||||||
|
],
|
||||||
|
'category_options' => [
|
||||||
|
'uncategorized' => 'uncategorized',
|
||||||
|
'arts' => 'Arts',
|
||||||
|
'business' => 'Business',
|
||||||
|
'comedy' => 'Comedy',
|
||||||
|
'education' => 'Education',
|
||||||
|
'fiction' => 'Fiction',
|
||||||
|
'government' => 'Government',
|
||||||
|
'health_and_fitness' => 'Health & Fitness',
|
||||||
|
'history' => 'History',
|
||||||
|
'kids_and_family' => 'Kids & Family',
|
||||||
|
'leisure' => 'Leisure',
|
||||||
|
'music' => 'Music',
|
||||||
|
'news' => 'News',
|
||||||
|
'religion_and_spirituality' => 'Religion & Spirituality',
|
||||||
|
'science' => 'Science',
|
||||||
|
'society_and_culture' => 'Society & Culture',
|
||||||
|
'sports' => 'Sports',
|
||||||
|
'technology' => 'Technology',
|
||||||
|
'true_crime' => 'True Crime',
|
||||||
|
'tv_and_film' => 'TV & Film',
|
||||||
|
'books' => 'Books',
|
||||||
|
'design' => 'Design',
|
||||||
|
'fashion_and_beauty' => 'Fashion & Beauty',
|
||||||
|
'food' => 'Food',
|
||||||
|
'performing_arts' => 'Performing Arts',
|
||||||
|
'visual_arts' => 'Visual Arts',
|
||||||
|
'careers' => 'Careers',
|
||||||
|
'entrepreneurship' => 'Entrepreneurship',
|
||||||
|
'investing' => 'Investing',
|
||||||
|
'management' => 'Management',
|
||||||
|
'marketing' => 'Marketing',
|
||||||
|
'non_profit' => 'Non-Profit',
|
||||||
|
'comedy_interviews' => 'Comedy Interviews',
|
||||||
|
'improv' => 'Improv',
|
||||||
|
'stand_up' => 'Stand-Up',
|
||||||
|
'courses' => 'Courses',
|
||||||
|
'how_to' => 'How To',
|
||||||
|
'language_learning' => 'Language Learning',
|
||||||
|
'self-improvement' => 'Self-Improvement',
|
||||||
|
'comedy_fiction' => 'Comedy Fiction',
|
||||||
|
'drama' => 'Drama',
|
||||||
|
'science_fiction' => 'Science Fiction',
|
||||||
|
'alternative_health' => 'Alternative Health',
|
||||||
|
'fitness' => 'Fitness',
|
||||||
|
'medicine' => 'Medicine',
|
||||||
|
'mental_health' => 'Mental Health',
|
||||||
|
'nutrition' => 'Nutrition',
|
||||||
|
'sexuality' => 'Sexuality',
|
||||||
|
'education_for_kids' => 'Education for Kids',
|
||||||
|
'parenting' => 'Parenting',
|
||||||
|
'pets_and_animals' => 'Pets & Animals',
|
||||||
|
'stories_for_kids' => 'Stories for Kids',
|
||||||
|
'animation_and_manga' => 'Animation & Manga',
|
||||||
|
'automotive' => 'Automotive',
|
||||||
|
'aviation' => 'Aviation',
|
||||||
|
'crafts' => 'Crafts',
|
||||||
|
'games' => 'Games',
|
||||||
|
'hobbies' => 'Hobbies',
|
||||||
|
'home_and_garden' => 'Home & Garden',
|
||||||
|
'video_games' => 'Video Games',
|
||||||
|
'music_commentary' => 'Music Commentary',
|
||||||
|
'music_history' => 'Music History',
|
||||||
|
'music_interviews' => 'Music Interviews',
|
||||||
|
'business_news' => 'Business News',
|
||||||
|
'daily_news' => 'Daily News',
|
||||||
|
'entertainment_news' => 'Entertainment News',
|
||||||
|
'news_commentary' => 'News Commentary',
|
||||||
|
'politics' => 'Politics',
|
||||||
|
'sports_news' => 'Sports News',
|
||||||
|
'tech_news' => 'Tech News',
|
||||||
|
'buddhism' => 'Buddhism',
|
||||||
|
'christianity' => 'Christianity',
|
||||||
|
'hinduism' => 'Hinduism',
|
||||||
|
'islam' => 'Islam',
|
||||||
|
'judaism' => 'Judaism',
|
||||||
|
'religion' => 'Religion',
|
||||||
|
'spirituality' => 'Spirituality',
|
||||||
|
'astronomy' => 'Astronomy',
|
||||||
|
'chemistry' => 'Chemistry',
|
||||||
|
'earth_sciences' => 'Earth Sciences',
|
||||||
|
'life_sciences' => 'Life Sciences',
|
||||||
|
'mathematics' => 'Mathematics',
|
||||||
|
'natural_sciences' => 'Natural Sciences',
|
||||||
|
'nature' => 'Nature',
|
||||||
|
'physics' => 'Physics',
|
||||||
|
'social_sciences' => 'Social Sciences',
|
||||||
|
'documentary' => 'Documentary',
|
||||||
|
'personal_journals' => 'Personal Journals',
|
||||||
|
'philosophy' => 'Philosophy',
|
||||||
|
'places_and_travel' => 'Places & Travel',
|
||||||
|
'relationships' => 'Relationships',
|
||||||
|
'baseball' => 'Baseball',
|
||||||
|
'basketball' => 'Basketball',
|
||||||
|
'cricket' => 'Cricket',
|
||||||
|
'fantasy_sports' => 'Fantasy Sports',
|
||||||
|
'football' => 'Football',
|
||||||
|
'golf' => 'Golf',
|
||||||
|
'hockey' => 'Hockey',
|
||||||
|
'rugby' => 'Rugby',
|
||||||
|
'running' => 'Running',
|
||||||
|
'soccer' => 'Soccer',
|
||||||
|
'swimming' => 'Swimming',
|
||||||
|
'tennis' => 'Tennis',
|
||||||
|
'volleyball' => 'Volleyball',
|
||||||
|
'wilderness' => 'Wilderness',
|
||||||
|
'wrestling' => 'Wrestling',
|
||||||
|
'after_shows' => 'After Shows',
|
||||||
|
'film_history' => 'Film History',
|
||||||
|
'film_interviews' => 'Film Interviews',
|
||||||
|
'film_reviews' => 'Film Reviews',
|
||||||
|
'tv_reviews' => 'TV Reviews',
|
||||||
|
],
|
||||||
|
];
|
@ -10,7 +10,7 @@ class LanguageModel extends Model
|
|||||||
protected $primaryKey = 'id';
|
protected $primaryKey = 'id';
|
||||||
|
|
||||||
protected $allowedFields = [
|
protected $allowedFields = [
|
||||||
'code',
|
'code', 'native_name'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $returnType = 'App\Entities\Language';
|
protected $returnType = 'App\Entities\Language';
|
@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use CodeIgniter\CLI\CLI;
|
use CodeIgniter\CLI\CLI;
|
||||||
|
|
||||||
CLI::error('ERROR: ' . $code);
|
CLI::error('ERROR: ' . $code);
|
@ -5,11 +5,11 @@ Message: <?= $message, "\n"; ?>
|
|||||||
Filename: <?= $exception->getFile(), "\n"; ?>
|
Filename: <?= $exception->getFile(), "\n"; ?>
|
||||||
Line Number: <?= $exception->getLine(); ?>
|
Line Number: <?= $exception->getLine(); ?>
|
||||||
|
|
||||||
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === true): ?>
|
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE === true) : ?>
|
||||||
|
|
||||||
Backtrace:
|
Backtrace:
|
||||||
<?php foreach ($exception->getTrace() as $error): ?>
|
<?php foreach ($exception->getTrace() as $error) : ?>
|
||||||
<?php if (isset($error['file'])): ?>
|
<?php if (isset($error['file'])) : ?>
|
||||||
<?= trim('-' . $error['line'] . ' - ' . $error['file'] . '::' . $error['function']) . "\n" ?>
|
<?= trim('-' . $error['line'] . ' - ' . $error['file'] . '::' . $error['function']) . "\n" ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
@ -5,16 +5,13 @@
|
|||||||
var tabLinks = new Array();
|
var tabLinks = new Array();
|
||||||
var contentDivs = new Array();
|
var contentDivs = new Array();
|
||||||
|
|
||||||
function init ()
|
function init() {
|
||||||
{
|
|
||||||
|
|
||||||
// Grab the tab links and content divs from the page
|
// Grab the tab links and content divs from the page
|
||||||
var tabListItems = document.getElementById('tabs').childNodes;
|
var tabListItems = document.getElementById('tabs').childNodes;
|
||||||
console.log(tabListItems);
|
console.log(tabListItems);
|
||||||
for (var i = 0; i < tabListItems.length; i ++)
|
for (var i = 0; i < tabListItems.length; i++) {
|
||||||
{
|
if (tabListItems[i].nodeName == "LI") {
|
||||||
if (tabListItems[i].nodeName == "LI")
|
|
||||||
{
|
|
||||||
var tabLink = getFirstChildWithTagName(tabListItems[i], 'A');
|
var tabLink = getFirstChildWithTagName(tabListItems[i], 'A');
|
||||||
var id = getHash(tabLink.getAttribute('href'));
|
var id = getHash(tabLink.getAttribute('href'));
|
||||||
tabLinks[id] = tabLink;
|
tabLinks[id] = tabLink;
|
||||||
@ -26,48 +23,40 @@ function init ()
|
|||||||
// highlight the first tab
|
// highlight the first tab
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
|
||||||
for (var id in tabLinks)
|
for (var id in tabLinks) {
|
||||||
{
|
|
||||||
tabLinks[id].onclick = showTab;
|
tabLinks[id].onclick = showTab;
|
||||||
tabLinks[id].onfocus = function () { this.blur() };
|
tabLinks[id].onfocus = function () { this.blur() };
|
||||||
if (i == 0)
|
if (i == 0) {
|
||||||
{
|
|
||||||
tabLinks[id].className = 'active';
|
tabLinks[id].className = 'active';
|
||||||
}
|
}
|
||||||
i ++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide all content divs except the first
|
// Hide all content divs except the first
|
||||||
var i = 0;
|
var i = 0;
|
||||||
|
|
||||||
for (var id in contentDivs)
|
for (var id in contentDivs) {
|
||||||
{
|
if (i != 0) {
|
||||||
if (i != 0)
|
|
||||||
{
|
|
||||||
console.log(contentDivs[id]);
|
console.log(contentDivs[id]);
|
||||||
contentDivs[id].className = 'content hide';
|
contentDivs[id].className = 'content hide';
|
||||||
}
|
}
|
||||||
i ++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
function showTab ()
|
function showTab() {
|
||||||
{
|
|
||||||
var selectedId = getHash(this.getAttribute('href'));
|
var selectedId = getHash(this.getAttribute('href'));
|
||||||
|
|
||||||
// Highlight the selected tab, and dim all others.
|
// Highlight the selected tab, and dim all others.
|
||||||
// Also show the selected content div, and hide all others.
|
// Also show the selected content div, and hide all others.
|
||||||
for (var id in contentDivs)
|
for (var id in contentDivs) {
|
||||||
{
|
if (id == selectedId) {
|
||||||
if (id == selectedId)
|
|
||||||
{
|
|
||||||
tabLinks[id].className = 'active';
|
tabLinks[id].className = 'active';
|
||||||
contentDivs[id].className = 'content';
|
contentDivs[id].className = 'content';
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
tabLinks[id].className = '';
|
tabLinks[id].className = '';
|
||||||
contentDivs[id].className = 'content hide';
|
contentDivs[id].className = 'content hide';
|
||||||
}
|
}
|
||||||
@ -79,12 +68,9 @@ function showTab ()
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
function getFirstChildWithTagName (element, tagName)
|
function getFirstChildWithTagName(element, tagName) {
|
||||||
{
|
for (var i = 0; i < element.childNodes.length; i++) {
|
||||||
for (var i = 0; i < element.childNodes.length; i ++)
|
if (element.childNodes[i].nodeName == tagName) {
|
||||||
{
|
|
||||||
if (element.childNodes[i].nodeName == tagName)
|
|
||||||
{
|
|
||||||
return element.childNodes[i];
|
return element.childNodes[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,30 +78,25 @@ function getFirstChildWithTagName (element, tagName)
|
|||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
function getHash (url)
|
function getHash(url) {
|
||||||
{
|
|
||||||
var hashPos = url.lastIndexOf('#');
|
var hashPos = url.lastIndexOf('#');
|
||||||
return url.substring(hashPos + 1);
|
return url.substring(hashPos + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
function toggle (elem)
|
function toggle(elem) {
|
||||||
{
|
|
||||||
elem = document.getElementById(elem);
|
elem = document.getElementById(elem);
|
||||||
|
|
||||||
if (elem.style && elem.style['display'])
|
if (elem.style && elem.style['display']) {
|
||||||
{
|
|
||||||
// Only works with the "style" attr
|
// Only works with the "style" attr
|
||||||
var disp = elem.style['display'];
|
var disp = elem.style['display'];
|
||||||
}
|
}
|
||||||
else if (elem.currentStyle)
|
else if (elem.currentStyle) {
|
||||||
{
|
|
||||||
// For MSIE, naturally
|
// For MSIE, naturally
|
||||||
var disp = elem.currentStyle['display'];
|
var disp = elem.currentStyle['display'];
|
||||||
}
|
}
|
||||||
else if (window.getComputedStyle)
|
else if (window.getComputedStyle) {
|
||||||
{
|
|
||||||
// For most other browsers
|
// For most other browsers
|
||||||
var disp = document.defaultView.getComputedStyle(elem, null).getPropertyValue('display');
|
var disp = document.defaultView.getComputedStyle(elem, null).getPropertyValue('display');
|
||||||
}
|
}
|
95
app/Views/errors/html/error_404.php
Normal file
95
app/Views/errors/html/error_404.php
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>404 Page Not Found</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div.logo {
|
||||||
|
height: 200px;
|
||||||
|
width: 155px;
|
||||||
|
display: inline-block;
|
||||||
|
opacity: 0.08;
|
||||||
|
position: absolute;
|
||||||
|
top: 2rem;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -73px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
background: #fafafa;
|
||||||
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
color: #777;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: lighter;
|
||||||
|
letter-spacing: 0.8;
|
||||||
|
font-size: 3rem;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
color: #222;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
max-width: 1024px;
|
||||||
|
margin: 5rem auto;
|
||||||
|
padding: 2rem;
|
||||||
|
background: #fff;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #efefef;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
white-space: normal;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background: #fafafa;
|
||||||
|
border: 1px solid #efefef;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 2rem;
|
||||||
|
border-top: 1px solid #efefef;
|
||||||
|
padding: 1em 2em 0 2em;
|
||||||
|
font-size: 85%;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active,
|
||||||
|
a:link,
|
||||||
|
a:visited {
|
||||||
|
color: #dd4814;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="wrap">
|
||||||
|
<h1>404 - File Not Found</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<?php if (!empty($message) && $message !== '(null)') : ?>
|
||||||
|
<?= esc($message) ?>
|
||||||
|
<?php else : ?>
|
||||||
|
Sorry! Cannot seem to find the page you were looking for.
|
||||||
|
<?php endif ?>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -1,6 +1,7 @@
|
|||||||
<?php $error_id = uniqid('error', true); ?>
|
<?php $error_id = uniqid('error', true); ?>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="robots" content="noindex">
|
<meta name="robots" content="noindex">
|
||||||
@ -14,6 +15,7 @@
|
|||||||
<?= file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.js') ?>
|
<?= file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.js') ?>
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body onload="init()">
|
<body onload="init()">
|
||||||
|
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
@ -22,8 +24,7 @@
|
|||||||
<h1><?= htmlspecialchars($title, ENT_SUBSTITUTE, 'UTF-8'), ($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
|
<h1><?= htmlspecialchars($title, ENT_SUBSTITUTE, 'UTF-8'), ($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
|
||||||
<p>
|
<p>
|
||||||
<?= $exception->getMessage() ?>
|
<?= $exception->getMessage() ?>
|
||||||
<a href="https://www.google.com/search?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>"
|
<a href="https://www.google.com/search?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>" rel="noreferrer" target="_blank">search →</a>
|
||||||
rel="noreferrer" target="_blank">search →</a>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -62,14 +63,11 @@
|
|||||||
<li>
|
<li>
|
||||||
<p>
|
<p>
|
||||||
<!-- Trace info -->
|
<!-- Trace info -->
|
||||||
<?php if (isset($row['file']) && is_file($row['file'])) :?>
|
<?php if (isset($row['file']) && is_file($row['file'])) : ?>
|
||||||
<?php
|
<?php
|
||||||
if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once']))
|
if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'])) {
|
||||||
{
|
|
||||||
echo $row['function'] . ' ' . static::cleanPath($row['file']);
|
echo $row['function'] . ' ' . static::cleanPath($row['file']);
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
echo static::cleanPath($row['file']) . ' : ' . $row['line'];
|
echo static::cleanPath($row['file']) . ' : ' . $row['line'];
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@ -80,7 +78,7 @@
|
|||||||
<!-- Class/Method -->
|
<!-- Class/Method -->
|
||||||
<?php if (isset($row['class'])) : ?>
|
<?php if (isset($row['class'])) : ?>
|
||||||
— <?= $row['class'] . $row['type'] . $row['function'] ?>
|
— <?= $row['class'] . $row['type'] . $row['function'] ?>
|
||||||
<?php if (! empty($row['args'])) : ?>
|
<?php if (!empty($row['args'])) : ?>
|
||||||
<?php $args_id = $error_id . 'args' . $index ?>
|
<?php $args_id = $error_id . 'args' . $index ?>
|
||||||
( <a href="#" onclick="return toggle('<?= $args_id ?>');">arguments</a> )
|
( <a href="#" onclick="return toggle('<?= $args_id ?>');">arguments</a> )
|
||||||
<div class="args" id="<?= $args_id ?>">
|
<div class="args" id="<?= $args_id ?>">
|
||||||
@ -89,15 +87,16 @@
|
|||||||
<?php
|
<?php
|
||||||
$params = null;
|
$params = null;
|
||||||
// Reflection by name is not available for closure function
|
// Reflection by name is not available for closure function
|
||||||
if (substr( $row['function'], -1 ) !== '}')
|
if (substr($row['function'], -1) !== '}') {
|
||||||
{
|
$mirror = isset($row['class']) ? new \ReflectionMethod($row['class'], $row['function']) : new \ReflectionFunction($row['function']);
|
||||||
$mirror = isset( $row['class'] ) ? new \ReflectionMethod( $row['class'], $row['function'] ) : new \ReflectionFunction( $row['function'] );
|
|
||||||
$params = $mirror->getParameters();
|
$params = $mirror->getParameters();
|
||||||
}
|
}
|
||||||
foreach ($row['args'] as $key => $value) : ?>
|
foreach ($row['args'] as $key => $value) : ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><code><?= htmlspecialchars(isset($params[$key]) ? '$' . $params[$key]->name : "#$key", ENT_SUBSTITUTE, 'UTF-8') ?></code></td>
|
<td><code><?= htmlspecialchars(isset($params[$key]) ? '$' . $params[$key]->name : "#$key", ENT_SUBSTITUTE, 'UTF-8') ?></code></td>
|
||||||
<td><pre><?= print_r($value, true) ?></pre></td>
|
<td>
|
||||||
|
<pre><?= print_r($value, true) ?></pre>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
|
|
||||||
@ -108,7 +107,7 @@
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if (! isset($row['class']) && isset($row['function'])) : ?>
|
<?php if (!isset($row['class']) && isset($row['function'])) : ?>
|
||||||
— <?= $row['function'] ?>()
|
— <?= $row['function'] ?>()
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</p>
|
</p>
|
||||||
@ -129,8 +128,7 @@
|
|||||||
<!-- Server -->
|
<!-- Server -->
|
||||||
<div class="content" id="server">
|
<div class="content" id="server">
|
||||||
<?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
|
<?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
|
||||||
<?php if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var]))
|
<?php if (empty($GLOBALS[$var]) || !is_array($GLOBALS[$var])) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
} ?>
|
} ?>
|
||||||
|
|
||||||
@ -150,7 +148,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<?php if (is_string($value)) : ?>
|
<?php if (is_string($value)) : ?>
|
||||||
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
||||||
<?php else: ?>
|
<?php else : ?>
|
||||||
<?= '<pre>' . print_r($value, true) ?>
|
<?= '<pre>' . print_r($value, true) ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
@ -163,7 +161,7 @@
|
|||||||
|
|
||||||
<!-- Constants -->
|
<!-- Constants -->
|
||||||
<?php $constants = get_defined_constants(true); ?>
|
<?php $constants = get_defined_constants(true); ?>
|
||||||
<?php if (! empty($constants['user'])) : ?>
|
<?php if (!empty($constants['user'])) : ?>
|
||||||
<h3>Constants</h3>
|
<h3>Constants</h3>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
@ -178,9 +176,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php if (! is_array($value) && ! is_object($value)) : ?>
|
<?php if (!is_array($value) && !is_object($value)) : ?>
|
||||||
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
||||||
<?php else: ?>
|
<?php else : ?>
|
||||||
<?= '<pre>' . print_r($value, true) ?>
|
<?= '<pre>' . print_r($value, true) ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
@ -232,8 +230,7 @@
|
|||||||
|
|
||||||
<?php $empty = true; ?>
|
<?php $empty = true; ?>
|
||||||
<?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
|
<?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
|
||||||
<?php if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var]))
|
<?php if (empty($GLOBALS[$var]) || !is_array($GLOBALS[$var])) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
} ?>
|
} ?>
|
||||||
|
|
||||||
@ -253,9 +250,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
<td><?= htmlspecialchars($key, ENT_IGNORE, 'UTF-8') ?></td>
|
||||||
<td>
|
<td>
|
||||||
<?php if (! is_array($value) && ! is_object($value)) : ?>
|
<?php if (!is_array($value) && !is_object($value)) : ?>
|
||||||
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
<?= htmlspecialchars($value, ENT_SUBSTITUTE, 'UTF-8') ?>
|
||||||
<?php else: ?>
|
<?php else : ?>
|
||||||
<?= '<pre>' . print_r($value, true) ?>
|
<?= '<pre>' . print_r($value, true) ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
@ -275,7 +272,7 @@
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php $headers = $request->getHeaders(); ?>
|
<?php $headers = $request->getHeaders(); ?>
|
||||||
<?php if (! empty($headers)) : ?>
|
<?php if (!empty($headers)) : ?>
|
||||||
|
|
||||||
<h3>Headers</h3>
|
<h3>Headers</h3>
|
||||||
|
|
||||||
@ -288,12 +285,10 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php foreach ($headers as $value) : ?>
|
<?php foreach ($headers as $value) : ?>
|
||||||
<?php if (empty($value))
|
<?php if (empty($value)) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
} ?>
|
} ?>
|
||||||
<?php if (! is_array($value))
|
<?php if (!is_array($value)) {
|
||||||
{
|
|
||||||
$value = [$value];
|
$value = [$value];
|
||||||
} ?>
|
} ?>
|
||||||
<?php foreach ($value as $h) : ?>
|
<?php foreach ($value as $h) : ?>
|
||||||
@ -323,7 +318,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<?php $headers = $response->getHeaders(); ?>
|
<?php $headers = $response->getHeaders(); ?>
|
||||||
<?php if (! empty($headers)) : ?>
|
<?php if (!empty($headers)) : ?>
|
||||||
<?php natsort($headers) ?>
|
<?php natsort($headers) ?>
|
||||||
|
|
||||||
<h3>Headers</h3>
|
<h3>Headers</h3>
|
||||||
@ -353,8 +348,8 @@
|
|||||||
<?php $files = get_included_files(); ?>
|
<?php $files = get_included_files(); ?>
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<?php foreach ($files as $file) :?>
|
<?php foreach ($files as $file) : ?>
|
||||||
<li><?= htmlspecialchars( static::cleanPath($file), ENT_SUBSTITUTE, 'UTF-8') ?></li>
|
<li><?= htmlspecialchars(static::cleanPath($file), ENT_SUBSTITUTE, 'UTF-8') ?></li>
|
||||||
<?php endforeach ?>
|
<?php endforeach ?>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
@ -398,4 +393,5 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -1,5 +1,6 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="robots" content="noindex">
|
<meta name="robots" content="noindex">
|
||||||
@ -10,8 +11,8 @@
|
|||||||
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
|
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
|
|
||||||
|
<body>
|
||||||
<div class="container text-center">
|
<div class="container text-center">
|
||||||
|
|
||||||
<h1 class="headline">Whoops!</h1>
|
<h1 class="headline">Whoops!</h1>
|
||||||
@ -19,7 +20,6 @@
|
|||||||
<p class="lead">We seem to have hit a snag. Please try again later...</p>
|
<p class="lead">We seem to have hit a snag. Please try again later...</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
22
app/Views/home.php
Normal file
22
app/Views/home.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?= $this->extend('layouts/default') ?>
|
||||||
|
|
||||||
|
<?= $this->section('content') ?>
|
||||||
|
|
||||||
|
<h1 class="mb-2 text-xl"><?= lang("Home.all_podcasts") ?> (<?= count($podcasts) ?>)</h1>
|
||||||
|
<section class="flex flex-wrap">
|
||||||
|
<?php if ($podcasts) : ?>
|
||||||
|
<?php foreach ($podcasts as $podcast) : ?>
|
||||||
|
<a href="/@<?= $podcast->name ?>">
|
||||||
|
<article class="w-48 p-2 mb-4 mr-4 border shadow-sm hover:bg-gray-100 hover:shadow">
|
||||||
|
<img alt="<?= $podcast->title ?>" src="<?= $podcast->image ?>" class="object-cover w-full h-40 mb-2" />
|
||||||
|
<h2 class="font-semibold leading-tight"><?= $podcast->title ?></h2>
|
||||||
|
<p class="text-gray-600">@<?= $podcast->name ?></p>
|
||||||
|
</article>
|
||||||
|
</a>
|
||||||
|
<?php endforeach ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<p class="italic"><?= lang("Home.no_podcast") ?></p>
|
||||||
|
<?php endif ?>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<?= $this->endSection() ?>
|
87170
app/Views/index.css
Normal file
87170
app/Views/index.css
Normal file
File diff suppressed because it is too large
Load Diff
28
app/Views/layouts/default.php
Normal file
28
app/Views/layouts/default.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Castopod</title>
|
||||||
|
<meta name="description" content="Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience.">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="shortcut icon" type="image/png" href="/favicon.ico" />
|
||||||
|
<link rel="stylesheet" href="/index.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="flex flex-col min-h-screen mx-auto">
|
||||||
|
<header class="border-b">
|
||||||
|
<div class="container flex items-center justify-between px-2 py-4 mx-auto">
|
||||||
|
<a href="/" class="text-2xl">Castopod</a>
|
||||||
|
<nav>
|
||||||
|
<a class="px-4 py-2 border hover:bg-gray-100" href="/podcasts/create">New podcast</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="container flex-1 px-4 py-10 mx-auto">
|
||||||
|
<?= $this->renderSection('content') ?>
|
||||||
|
</main>
|
||||||
|
<footer class="container px-2 py-4 mx-auto text-sm text-right border-t">
|
||||||
|
Powered by <a class="underline hover:no-underline" href="https://code.podlibre.org/podlibre/castopod">Castopod</a>, a <a class="underline hover:no-underline" href="https://podlibre.org/">Podlibre</a> initiative.
|
||||||
|
</footer>
|
||||||
|
</body>
|
110
app/Views/podcasts/create.php
Normal file
110
app/Views/podcasts/create.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?= $this->extend('layouts/default') ?>
|
||||||
|
|
||||||
|
<?= $this->section('content') ?>
|
||||||
|
|
||||||
|
<h1 class="mb-6 text-xl"><?= lang("Podcasts.create") ?></h1>
|
||||||
|
|
||||||
|
<!-- <div class="mb-8">
|
||||||
|
\Config\Services::validation()->listErrors()
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<?= form_open_multipart('podcasts/create', ["method" => "post", "class" => "flex flex-col max-w-md"]) ?>
|
||||||
|
<?= csrf_field() ?>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="title"><?= lang("Podcasts.form.title") ?></label>
|
||||||
|
<input type="text" class="form-input" id="title" name="title" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="name"><?= lang("Podcasts.form.name") ?></label>
|
||||||
|
<input type="text" class="form-input" id="name" name="name" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="description"><?= lang("Podcasts.form.description") ?></label>
|
||||||
|
<textarea class="form-textarea" id="description" name="description" required></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="episode_description_footer"><?= lang("Podcasts.form.episode_description_footer") ?></label>
|
||||||
|
<textarea class="form-textarea" id="episode_description_footer" name="episode_description_footer"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="image"><?= lang("Podcasts.form.image") ?></label>
|
||||||
|
<input type="file" class="form-input" id="image" name="image" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="language"><?= lang("Podcasts.form.language") ?></label>
|
||||||
|
<select id="language" name="language" autocomplete="off" class="form-select" required>
|
||||||
|
<?php foreach ($languages as $language) : ?>
|
||||||
|
<option <?= ($language->code == $browser_lang) ? "selected='selected'" : "" ?> value="<?= $language->code ?>"><?= $language->native_name ?></option>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="category"><?= lang("Podcasts.form.category") ?></label>
|
||||||
|
<select id="category" name="category" class="form-select" required>
|
||||||
|
<?php foreach ($categories as $category) : ?>
|
||||||
|
<option value="<?= $category->code ?>"><?= lang("Podcasts.category_options." . $category->code) ?></option>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="inline-flex items-center mb-4">
|
||||||
|
<input type="checkbox" id="explicit" name="explicit" class="form-checkbox" />
|
||||||
|
<label for="explicit" class="pl-2"><?= lang("Podcasts.form.explicit") ?></label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="author"><?= lang("Podcasts.form.author") ?></label>
|
||||||
|
<input type="text" class="form-input" id="author" name="author" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="owner_name"><?= lang("Podcasts.form.owner_name") ?></label>
|
||||||
|
<input type="text" class="form-input" id="owner_name" name="owner_name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="owner_email"><?= lang("Podcasts.form.owner_email") ?></label>
|
||||||
|
<input type="email" class="form-input" id="owner_email" name="owner_email" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<fieldset class="mb-4">
|
||||||
|
<legend><?= lang("Podcasts.form.type.label") ?></legend>
|
||||||
|
<input type="radio" class="form-radio" value="episodic" id="episodic" name="type" checked="checked" />
|
||||||
|
<label for="episodic"><?= lang("Podcasts.form.type.episodic") ?></label><br />
|
||||||
|
|
||||||
|
<input type="radio" class="form-radio" value="serial" id="serial" name="type" />
|
||||||
|
<label for="serial"><?= lang("Podcasts.form.type.serial") ?></label><br />
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="copyright"><?= lang("Podcasts.form.copyright") ?></label>
|
||||||
|
<input type="text" class="form-input" id="copyright" name="copyright" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="inline-flex items-center mb-4">
|
||||||
|
<input type="checkbox" id="block" name="block" class="form-checkbox" />
|
||||||
|
<label for="block" class="pl-2"><?= lang("Podcasts.form.block") ?></label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="inline-flex items-center mb-4">
|
||||||
|
<input type="checkbox" id="complete" name="complete" class="form-checkbox" />
|
||||||
|
<label for="complete" class="pl-2"><?= lang("Podcasts.form.complete") ?></label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col mb-4">
|
||||||
|
<label for="custom_html_head"><?= esc(lang("Podcasts.form.custom_html_head")) ?></label>
|
||||||
|
<textarea class="form-textarea" id="custom_html_head" name="custom_html_head"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" name="submit" class="self-end px-4 py-2 bg-gray-200"><?= lang("Podcasts.form.submit") ?></button>
|
||||||
|
<?= form_close() ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?= $this->endSection() ?>
|
7
app/Views/podcasts/view.php
Normal file
7
app/Views/podcasts/view.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?= $this->extend('layouts/default') ?>
|
||||||
|
|
||||||
|
<?= $this->section('content') ?>
|
||||||
|
<h1 class="text-xl"><?= $podcast->title ?></h1>
|
||||||
|
<img src="<?= base_url($podcast->image) ?>" alt="Podcast cover" />
|
||||||
|
|
||||||
|
<?= $this->endSection() ?>
|
@ -1,11 +1,14 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<title>403 Forbidden</title>
|
<title>403 Forbidden</title>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<p>Directory access is forbidden.</p>
|
<p>Directory access is forbidden.</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
1
commitlint.config.js
Normal file
1
commitlint.config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = { extends: ['@commitlint/config-conventional'] }
|
1887
composer.lock
generated
Normal file
1887
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
volumes:
|
volumes:
|
||||||
- ./src:/castopod
|
- .:/castopod
|
||||||
depends_on:
|
depends_on:
|
||||||
- mariadb
|
- mariadb
|
||||||
networks:
|
networks:
|
||||||
@ -21,7 +21,7 @@ services:
|
|||||||
|
|
||||||
mariadb:
|
mariadb:
|
||||||
image: mariadb:latest
|
image: mariadb:latest
|
||||||
container_name: "castopod_mariadb"
|
container_name: castopod_mariadb
|
||||||
ports:
|
ports:
|
||||||
- 3306:3306
|
- 3306:3306
|
||||||
volumes:
|
volumes:
|
||||||
@ -36,7 +36,7 @@ services:
|
|||||||
|
|
||||||
phpmyadmin:
|
phpmyadmin:
|
||||||
image: phpmyadmin/phpmyadmin:latest
|
image: phpmyadmin/phpmyadmin:latest
|
||||||
container_name: "castopod_phpmyadmin"
|
container_name: castopod_phpmyadmin
|
||||||
environment:
|
environment:
|
||||||
PMA_HOST: mariadb
|
PMA_HOST: mariadb
|
||||||
PMA_PORT: 3306
|
PMA_PORT: 3306
|
||||||
@ -51,13 +51,22 @@ services:
|
|||||||
|
|
||||||
composer:
|
composer:
|
||||||
image: composer:latest
|
image: composer:latest
|
||||||
container_name: composer
|
container_name: castopod_composer
|
||||||
volumes:
|
volumes:
|
||||||
- ./src:/var/www/html
|
- .:/var/www/html
|
||||||
working_dir: /var/www/html
|
working_dir: /var/www/html
|
||||||
networks:
|
networks:
|
||||||
- castopod
|
- castopod
|
||||||
|
|
||||||
|
node:
|
||||||
|
image: node:lts
|
||||||
|
container_name: castopod_node
|
||||||
|
volumes:
|
||||||
|
- .:/usr/src/app
|
||||||
|
working_dir: /usr/src/app
|
||||||
|
networks:
|
||||||
|
- castopod
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mariadb:
|
mariadb:
|
||||||
phpmyadmin:
|
phpmyadmin:
|
||||||
|
194
docs/setup-development.md
Normal file
194
docs/setup-development.md
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# Setup your development environment <!-- omit in toc -->
|
||||||
|
|
||||||
|
## Table of contents <!-- omit in toc -->
|
||||||
|
|
||||||
|
- [Introduction](#introduction)
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [Start docker containers](#start-docker-containers)
|
||||||
|
- [Initialize and populate database](#initialize-and-populate-database)
|
||||||
|
- [Install/Update app dependencies](#installupdate-app-dependencies)
|
||||||
|
- [Start hacking](#start-hacking)
|
||||||
|
- [Going Further](#going-further)
|
||||||
|
- [Useful docker / docker-compose commands](#useful-docker--docker-compose-commands)
|
||||||
|
- [Developing inside a Container](#developing-inside-a-container)
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Castopod is a web app based on the `php` framework [CodeIgniter 4](https://codeigniter.com).
|
||||||
|
|
||||||
|
To setup a dev environment, we use [Docker](https://www.docker.com/). A `docker-compose.yml` and `Dockerfile` are included in the project's root folder to help you kickstart your contribution.
|
||||||
|
|
||||||
|
> Know that you don't need any prior knowledge of Docker to follow the next steps. However, if you wish to use your own environment, feel free to do so!
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
0. Install [docker desktop](https://www.docker.com/products/docker-desktop).
|
||||||
|
|
||||||
|
1. Clone castopod project by running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://code.podlibre.org/podlibre/castopod.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create a `.env` file with the minimum required config to connect the app to the database:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
CI_ENVIRONMENT = development
|
||||||
|
|
||||||
|
database.default.hostname = mariadb
|
||||||
|
database.default.database = castopod
|
||||||
|
database.default.username = podlibre
|
||||||
|
database.default.password = castopod
|
||||||
|
```
|
||||||
|
|
||||||
|
> _NB._ You can tweak your environment by setting more environment variables in your custom `.env` file. See the `env` for examples or the [CodeIgniter4 User Guide](https://codeigniter.com/user_guide/index.html) for more info.
|
||||||
|
|
||||||
|
3. Add the repository you've cloned to docker desktop's `Settings` > `Resources` > `File Sharing`.
|
||||||
|
4. Install castopod's php dependencies
|
||||||
|
|
||||||
|
> The project's php dependencies aren't included in the repository, you have to download them using the composer service defined in `docker-compose.yml`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose run --rm composer install --ignore-platform-reqs
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Install castopod's js dependencies
|
||||||
|
|
||||||
|
> The project's js dependencies aren't included in the repository, you have to download them using the node service defined in `docker-compose.yml`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose run --rm node npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Build styles using postcss
|
||||||
|
|
||||||
|
> To generate the `public/index.css` file, you must run the following command.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose run --rm node npm run build:css
|
||||||
|
```
|
||||||
|
|
||||||
|
## Start docker containers
|
||||||
|
|
||||||
|
Go to project's root folder and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# starts all services declared in docker-compose.yml file
|
||||||
|
# -d option starts the containers in the background
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# See all running processes (you should see 3 processes running)
|
||||||
|
docker ps
|
||||||
|
|
||||||
|
# Alternatively, you can check all processes (you should see composer with an Exited status)
|
||||||
|
docker ps -a
|
||||||
|
```
|
||||||
|
|
||||||
|
> The `docker-compose up -d` command will boot 3 containers in the background:
|
||||||
|
>
|
||||||
|
> - `castopod_app`: a php based container with codeigniter requirements installed
|
||||||
|
> - `castopod_mariadb`: a [mariadb](https://mariadb.org/) server for persistent data
|
||||||
|
> - `castopod_phpmyadmin`: a phpmyadmin server to visualize the mariadb database
|
||||||
|
>
|
||||||
|
> _NB._ `./mariadb`, `./phpmyadmin` folders will be mounted in the project's root directory to persist data and logs.
|
||||||
|
|
||||||
|
## Initialize and populate database
|
||||||
|
|
||||||
|
Build the database with the migrate command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# loads the database schema during first migration
|
||||||
|
docker-compose run --rm app php spark migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
Populate the database with the required data:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Populates all categories
|
||||||
|
docker-compose run --rm app php spark db:seed CategorySeeder
|
||||||
|
docker-compose run --rm app php spark db:seed LanguageSeeder
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install/Update app dependencies
|
||||||
|
|
||||||
|
Castopod uses `composer` to manage php dependencies and `npm` to manage javascript dependencies.
|
||||||
|
|
||||||
|
You can install / update the project's dependencies using both `composer` and `node` services:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# install php dependencies
|
||||||
|
docker-compose run --rm composer update --ignore-platform-reqs
|
||||||
|
|
||||||
|
# update php dependencies
|
||||||
|
docker-compose run --rm composer update --ignore-platform-reqs
|
||||||
|
```
|
||||||
|
|
||||||
|
> _NB._ composer commands look for the `composer.json` file to find castopod's php dependencies, all of which live in the `vendor/` folder. For more info, check out [Composer documentation](https://getcomposer.org/doc/).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# install js dependencies
|
||||||
|
docker-compose run --rm node npm install
|
||||||
|
|
||||||
|
# update js dependencies
|
||||||
|
docker-compose run --rm node npm update
|
||||||
|
```
|
||||||
|
|
||||||
|
> _NB._ npm commands look for the `package.json` file to find castopod's js dependencies, all of which live in the `node_modules/` folder. For more info, check out [NPM documentation](https://docs.npmjs.com/).
|
||||||
|
|
||||||
|
## Start hacking
|
||||||
|
|
||||||
|
You're all set! Start working your magic by updating the project's files! Help yourself to the [CodeIgniter4 User Guide](https://codeigniter.com/user_guide/index.html) for more insights.
|
||||||
|
|
||||||
|
To see your changes, go to:
|
||||||
|
|
||||||
|
- [localhost:8080](http://localhost:8080/) for the castopod app
|
||||||
|
- [localhost:8888](http://localhost:8888/) for the phpmyadmin interface:
|
||||||
|
|
||||||
|
- **Username**: podlibre
|
||||||
|
- **Password**: castopod
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Going Further
|
||||||
|
|
||||||
|
### Useful docker / docker-compose commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# monitor the app container
|
||||||
|
docker logs --tail 50 --follow --timestamps castopod_app
|
||||||
|
|
||||||
|
# monitor the mariadb container
|
||||||
|
docker logs --tail 50 --follow --timestamps castopod_mariadb
|
||||||
|
|
||||||
|
# monitor the phpmyadmin container
|
||||||
|
docker logs --tail 50 --follow --timestamps castopod_phpmyadmin
|
||||||
|
|
||||||
|
# restart docker containers
|
||||||
|
docker-compose restart
|
||||||
|
|
||||||
|
# Destroy all containers, opposite of `up` command
|
||||||
|
docker-compose down
|
||||||
|
```
|
||||||
|
|
||||||
|
Check [docker](https://docs.docker.com/engine/reference/commandline/docker/) and [docker-compose](https://docs.docker.com/compose/reference/) documentations for more insights.
|
||||||
|
|
||||||
|
## Developing inside a Container
|
||||||
|
|
||||||
|
If you're working in VSCode, you can take advantage of the `./.devcontainer/` folder. It defines a development container with preinstalled VSCode extensions so you don't have to worry about them. The container will be loaded with php, composer and git:
|
||||||
|
|
||||||
|
1. Install the VSCode extension [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||||
|
2. `Ctrl/Cmd + Shift + P` > `Open in container`
|
||||||
|
|
||||||
|
The VSCode window will reload inside the dev container.
|
||||||
|
|
||||||
|
You can check that the required packages are running in the console (`Terminal` > `New Terminal`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php -v
|
||||||
|
|
||||||
|
composer -V
|
||||||
|
|
||||||
|
git version
|
||||||
|
```
|
||||||
|
|
||||||
|
For more info, see [VSCode Remote Containers](https://code.visualstudio.com/docs/remote/containers)
|
4625
package-lock.json
generated
Normal file
4625
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
35
package.json
Normal file
35
package.json
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "castopod",
|
||||||
|
"version": "0.0.0-development",
|
||||||
|
"description": "Castopod is an open-source hosting platform made for podcasters who want engage and interact with their audience.",
|
||||||
|
"private": true,
|
||||||
|
"license": "AGPL-3.0-or-later",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://code.podlibre.org/podlibre/castopod.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build:css": "postcss app/Javascript/assets/styles/index.css -o app/Views/index.css",
|
||||||
|
"watch:css": "postcss app/Javascript/assets/styles/index.css -o app/Views/index.css -w",
|
||||||
|
"commit": "git-cz"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@commitlint/cli": "^8.3.5",
|
||||||
|
"@commitlint/config-conventional": "^8.3.4",
|
||||||
|
"@tailwindcss/custom-forms": "^0.2.1",
|
||||||
|
"cz-conventional-changelog": "^3.2.0",
|
||||||
|
"husky": "^4.2.5",
|
||||||
|
"postcss-cli": "^7.1.1",
|
||||||
|
"tailwindcss": "^1.4.6"
|
||||||
|
},
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"commitizen": {
|
||||||
|
"path": "cz-conventional-changelog"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: [
|
||||||
|
require('tailwindcss'),
|
||||||
|
require('autoprefixer'),
|
||||||
|
]
|
||||||
|
}
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.3 KiB |
51
src/.github/workflows/phpunit.yml
vendored
51
src/.github/workflows/phpunit.yml
vendored
@ -1,51 +0,0 @@
|
|||||||
name: PHPUnit
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- develop
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
main:
|
|
||||||
name: Build and test
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
php-versions: ['7.2', '7.3', '7.4']
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
|
|
||||||
- name: Setup PHP, with composer and extensions
|
|
||||||
uses: shivammathur/setup-php@master
|
|
||||||
with:
|
|
||||||
php-version: ${{ matrix.php-versions }}
|
|
||||||
tools: composer, pecl, phpunit
|
|
||||||
extensions: intl, json, mbstring, mysqlnd, xdebug, xml, sqlite3
|
|
||||||
coverage: xdebug
|
|
||||||
|
|
||||||
- name: Get composer cache directory
|
|
||||||
id: composer-cache
|
|
||||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
||||||
|
|
||||||
- name: Cache composer dependencies
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: ${{ steps.composer-cache.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
|
||||||
restore-keys: ${{ runner.os }}-composer-
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: composer install --no-progress --no-suggest --no-interaction --prefer-dist --optimize-autoloader
|
|
||||||
# To prevent rate limiting you may need to supply an OAuth token in Settings > Secrets
|
|
||||||
# env:
|
|
||||||
# https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens
|
|
||||||
# COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }}
|
|
||||||
|
|
||||||
- name: Test with phpunit
|
|
||||||
run: vendor/bin/phpunit --coverage-text
|
|
130
src/.gitignore
vendored
130
src/.gitignore
vendored
@ -1,130 +0,0 @@
|
|||||||
#-------------------------
|
|
||||||
# Operating Specific Junk Files
|
|
||||||
#-------------------------
|
|
||||||
|
|
||||||
# OS X
|
|
||||||
.DS_Store
|
|
||||||
.AppleDouble
|
|
||||||
.LSOverride
|
|
||||||
|
|
||||||
# OS X Thumbnails
|
|
||||||
._*
|
|
||||||
|
|
||||||
# Windows image file caches
|
|
||||||
Thumbs.db
|
|
||||||
ehthumbs.db
|
|
||||||
Desktop.ini
|
|
||||||
|
|
||||||
# Recycle Bin used on file shares
|
|
||||||
$RECYCLE.BIN/
|
|
||||||
|
|
||||||
# Windows Installer files
|
|
||||||
*.cab
|
|
||||||
*.msi
|
|
||||||
*.msm
|
|
||||||
*.msp
|
|
||||||
|
|
||||||
# Windows shortcuts
|
|
||||||
*.lnk
|
|
||||||
|
|
||||||
# Linux
|
|
||||||
*~
|
|
||||||
|
|
||||||
# KDE directory preferences
|
|
||||||
.directory
|
|
||||||
|
|
||||||
# Linux trash folder which might appear on any partition or disk
|
|
||||||
.Trash-*
|
|
||||||
|
|
||||||
#-------------------------
|
|
||||||
# Environment Files
|
|
||||||
#-------------------------
|
|
||||||
# These should never be under version control,
|
|
||||||
# as it poses a security risk.
|
|
||||||
.env
|
|
||||||
.vagrant
|
|
||||||
Vagrantfile
|
|
||||||
|
|
||||||
#-------------------------
|
|
||||||
# Temporary Files
|
|
||||||
#-------------------------
|
|
||||||
writable/cache/*
|
|
||||||
!writable/cache/index.html
|
|
||||||
|
|
||||||
writable/logs/*
|
|
||||||
!writable/logs/index.html
|
|
||||||
|
|
||||||
writable/session/*
|
|
||||||
!writable/session/index.html
|
|
||||||
|
|
||||||
writable/uploads/*
|
|
||||||
!writable/uploads/index.html
|
|
||||||
|
|
||||||
writable/debugbar/*
|
|
||||||
|
|
||||||
php_errors.log
|
|
||||||
|
|
||||||
#-------------------------
|
|
||||||
# User Guide Temp Files
|
|
||||||
#-------------------------
|
|
||||||
user_guide_src/build/*
|
|
||||||
user_guide_src/cilexer/build/*
|
|
||||||
user_guide_src/cilexer/dist/*
|
|
||||||
user_guide_src/cilexer/pycilexer.egg-info/*
|
|
||||||
|
|
||||||
#-------------------------
|
|
||||||
# Test Files
|
|
||||||
#-------------------------
|
|
||||||
tests/coverage*
|
|
||||||
|
|
||||||
# Don't save phpunit under version control.
|
|
||||||
phpunit
|
|
||||||
|
|
||||||
#-------------------------
|
|
||||||
# Composer
|
|
||||||
#-------------------------
|
|
||||||
vendor/
|
|
||||||
composer.lock
|
|
||||||
|
|
||||||
#-------------------------
|
|
||||||
# IDE / Development Files
|
|
||||||
#-------------------------
|
|
||||||
|
|
||||||
# Modules Testing
|
|
||||||
_modules/*
|
|
||||||
|
|
||||||
# phpenv local config
|
|
||||||
.php-version
|
|
||||||
|
|
||||||
# Jetbrains editors (PHPStorm, etc)
|
|
||||||
.idea/
|
|
||||||
*.iml
|
|
||||||
|
|
||||||
# Netbeans
|
|
||||||
nbproject/
|
|
||||||
build/
|
|
||||||
nbbuild/
|
|
||||||
dist/
|
|
||||||
nbdist/
|
|
||||||
nbactions.xml
|
|
||||||
nb-configuration.xml
|
|
||||||
.nb-gradle/
|
|
||||||
|
|
||||||
# Sublime Text
|
|
||||||
*.tmlanguage.cache
|
|
||||||
*.tmPreferences.cache
|
|
||||||
*.stTheme.cache
|
|
||||||
*.sublime-workspace
|
|
||||||
*.sublime-project
|
|
||||||
.phpintel
|
|
||||||
/api/
|
|
||||||
|
|
||||||
# Visual Studio Code
|
|
||||||
.vscode/
|
|
||||||
|
|
||||||
/results/
|
|
||||||
/phpunit*.xml
|
|
||||||
/.phpunit.*.cache
|
|
||||||
|
|
||||||
# Media files
|
|
||||||
public/media/*
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user