Compare commits

..

21 commits

Author SHA1 Message Date
0c48e7df70 Merge pull request 'develop' (#26) from develop into master
All checks were successful
/ build (push) Successful in 36s
Reviewed-on: #26
2024-11-15 12:43:45 +00:00
52d68dcf51 Merge pull request 'Task_19' (#25) from Task_19 into develop
Reviewed-on: #25
2024-11-15 12:42:59 +00:00
8388c2ccc6 Adds delete option 2024-11-15 13:41:52 +01:00
bfeb2a6e2a Merge remote-tracking branch 'origin/master'
All checks were successful
/ build (push) Successful in 36s
2024-11-12 20:36:10 +01:00
6c01948902 Adds README 2024-11-12 20:35:09 +01:00
da67fbc7b0 Merge pull request 'develop' (#24) from develop into master
All checks were successful
/ build (push) Successful in 36s
Reviewed-on: #24
2024-11-12 19:05:30 +00:00
bd47dda496 Merge pull request 'Add_Git_Notification' (#23) from Add_Git_Notification into develop
Reviewed-on: #23
2024-11-12 19:05:05 +00:00
0b3eae20a6 FEAT: Adds git messages on the bottom of the website 2024-11-12 20:04:10 +01:00
ff05142acc Merge pull request 'BUG: Improves Game Imports usage' (#22) from Task_20 into develop
Reviewed-on: #22
2024-11-12 18:41:28 +00:00
ab4ebe93a3 Merge pull request 'Improves game importer' (#16) from develop into master
All checks were successful
/ build (push) Successful in 36s
Reviewed-on: #16
2024-11-08 13:49:56 +00:00
5e77ba32c1 Merge pull request 'Made fromWhere nullable' (#15) from develop into master
All checks were successful
/ build (push) Successful in 35s
Reviewed-on: #15
2024-11-08 12:50:59 +00:00
07315422d3 Merge pull request 'Specify php version for proxy gen' (#14) from develop into master
All checks were successful
/ build (push) Successful in 34s
Reviewed-on: #14
2024-11-07 21:52:34 +00:00
296dd9730d Merge pull request 'Adds proxy generation as own container' (#13) from develop into master
Some checks failed
/ build (push) Failing after 36s
Reviewed-on: #13
2024-11-07 21:50:54 +00:00
4648507cdd Merge pull request 'Removed final from entity classes' (#12) from develop into master
All checks were successful
/ build (push) Successful in 34s
Reviewed-on: #12
2024-11-07 21:45:56 +00:00
e5b60e410d Merge pull request 'Fixes entrypoint for PHP' (#11) from develop into master
All checks were successful
/ build (push) Successful in 34s
Reviewed-on: #11
2024-11-07 21:44:04 +00:00
08142c5796 Merge pull request 'Adds proxies for doctrine on run' (#10) from develop into master
All checks were successful
/ build (push) Successful in 34s
Reviewed-on: #10
2024-11-07 21:38:01 +00:00
6c9c51d66d Merge pull request 'Removes writing to the ob if not expected' (#9) from develop into master
All checks were successful
/ build (push) Successful in 37s
Reviewed-on: #9
2024-11-07 21:25:56 +00:00
8a24f5b1cc Merge pull request 'Remove blocking exception' (#8) from develop into master
All checks were successful
/ build (push) Successful in 35s
Reviewed-on: #8
2024-11-07 21:19:38 +00:00
9e12deca4a Merge pull request 'Adds when error gets called' (#7) from develop into master
All checks were successful
/ build (push) Successful in 35s
Reviewed-on: #7
2024-11-07 21:16:02 +00:00
22d87b773d Merge pull request 'Adds loggin' (#6) from develop into master
All checks were successful
/ build (push) Successful in 35s
Reviewed-on: #6
2024-11-07 21:05:42 +00:00
aec0aa19d1 Merge pull request 'develop' (#5) from develop into master
All checks were successful
/ build (push) Successful in 37s
Reviewed-on: #5
2024-11-07 20:42:57 +00:00
9 changed files with 288 additions and 18 deletions

67
README.md Normal file
View file

@ -0,0 +1,67 @@
# Games Shop
This is the repository for the free games shop hosted on [shop.iedsoftworks.com](https://shop.iedsoftworks.com).
## Developers and local testers
To start a local variant of the site, you **need** Docker (with docker compose).
### 1 Cloning the repo
Start with cloning the repository
`git clone https://git.php.fail/neintonine/gamesshop.git`
and entering the folder for it
`cd gamesshop`
### 2 Installing dependencies
Then you need to install/build the NPM and composer portion.
There are two ways of doing it.
#### 2.1 Local NPM & Composer
If you have NodeJS and PHP8.3 with composer installed, you can simply run:
`npm install && npm run build && composer install`
#### 2.2 Docker
If you don't have those installed, and are unwilling to install them, you can use docker to install and build the required packages.
JS: `docker run --rm --volume "$PWD":/app -w /app node npm install && npm run build`
PHP: `docker run --rm --volume "$PWD":/app -w /app composer composer install --ignore-platform-req=ext-gd`
### 3 Creating the environment file
To run the site, you need a valid environment file.
#### 3.1 Copy the example
Under the folder 'config', you can find a `.env.example`-file, which you can use to create your enviroment file.
Start of by coping the file, and rename it to `.env`
`cp config/.env.example config/.env`
The example already includes settings for the database and logs.
#### 3.2 Adding your Discord-App
One thing, that the example doesn't contain is the discord app. Thats something you need to add.
Simply create an app in the [Discord Developer Portal](https://discord.com/developers/applications) and add the required values in the environment file
### 4 Creating the Database
Now after ensuring you have the dependencies and a valid environment file, we can create the database.
Again, if you have PHP installed you can just do: `php ./src/php/bin/doctrine.php orm:schema-tool:create`
If you don't want to do this, just let docker to do it:
```bash
docker run -v .:/app --rm -it php:8.3-cli php /app/src/php/bin/doctrine.php orm:schema-tool:create
```
### 5 Running the containers
Now finally, after creating the database, just go into the deploy folder (`cd deploy`) and start the compose file.
You may see, that there are two file (`docker-compose.yaml` and `docker-compose-dev.yml`). As you may expect the second is for local development so probably the one you should use.
The first does effectively the same thing, but for the production environment.
```bash
docker compose -f ./docker-compose-dev.yml up
```
Congratulations! The website should now boot up and after docker is done downloading, you should be able to use http://localhost:8080 to open the page.

View file

@ -7,6 +7,8 @@ import {init as initImport} from "./import";
import {init as initTable} from "./table"; import {init as initTable} from "./table";
import {init as initUserLists} from "./userlists"; import {init as initUserLists} from "./userlists";
import {initShare} from "./share"; import {initShare} from "./share";
import {init as initEditModal} from "./modals/edit";
import {init as initDeleteModal} from "./modals/delete";
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const triggerTabList = document.querySelectorAll('#key-tab button') const triggerTabList = document.querySelectorAll('#key-tab button')
@ -23,4 +25,7 @@ document.addEventListener('DOMContentLoaded', () => {
initTable(); initTable();
initUserLists(); initUserLists();
initShare(); initShare();
initEditModal();
initDeleteModal();
}) })

View file

@ -0,0 +1,42 @@
import {getCurrentlySelectedList} from "../userlists";
export function init() {
const modalElem = document.querySelector<HTMLDivElement>('#delete-list-modal');
if (!modalElem) {
return;
}
modalElem.addEventListener('show.bs.modal', () => {
const listSelect = document.querySelector<HTMLSelectElement>('#list-select');
const text = listSelect?.selectedOptions[0].text ?? '';
const listnameElem = modalElem.querySelector<HTMLSpanElement>('.list-name');
if (!listnameElem) {
return;
}
listnameElem.textContent = text;
})
modalElem.querySelector<HTMLButtonElement>('.js--yes')
?.addEventListener('click', async () => {
const id = getCurrentlySelectedList();
const formData = new FormData();
formData.append('id', id?.toString() ?? '-1');
const response = await fetch(
`/api/web/keys/list/delete`,
{
method: 'POST',
body: formData
}
);
if (!response.ok) {
throw new Error(response.statusText);
}
window.location.reload();
})
}

View file

@ -0,0 +1,18 @@
export function init() {
const modalElem = document.querySelector<HTMLDivElement>('#edit-list-modal');
if (!modalElem) {
return;
}
modalElem.addEventListener('show.bs.modal', () => {
const listSelect = document.querySelector<HTMLSelectElement>('#list-select');
const text = listSelect?.selectedOptions[0].text ?? '';
const listnameElem = modalElem.querySelector<HTMLSpanElement>('.list-name');
if (!listnameElem) {
return;
}
listnameElem.textContent = text;
})
}

View file

@ -0,0 +1,70 @@
<?php declare(strict_types=1);
namespace GamesShop\Routing\Api\Web;
use Doctrine\ORM\EntityManager;
use GamesShop\Entities\Games\Key;
use GamesShop\Entities\GamesList;
use GamesShop\Login\LoginHandler;
use GamesShop\Login\UserPermission;
use Laminas\Diactoros\Response;
use League\Route\Http\Exception\BadRequestException;
use League\Route\Http\Exception\ForbiddenException;
use League\Route\Http\Exception\UnauthorizedException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
final class DeleteKeyList
{
public function __construct(
private readonly LoginHandler $loginHandler,
private readonly EntityManager $entityManager
)
{
}
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
if (!$this->loginHandler->isLoggedIn()) {
throw new UnauthorizedException();
}
$user = $this->loginHandler->getCurrentUser();
if (!$user->getPermission()->hasLevel(UserPermission::PROVIDER)) {
throw new ForbiddenException();
}
$body = $request->getParsedBody();
if (!array_key_exists('id', $body)) {
throw new BadRequestException();
}
$id = $body['id'];
$list = $this->entityManager->getRepository(GamesList::class)->findOneBy(
[
'id' => $id,
'owner' => $user,
]
);
if ($list === null) {
throw new BadRequestException();
}
$this->entityManager->remove($list);
$keys = $this->entityManager->getRepository(Key::class)->findBy(
[
'list' => $list
]
);
foreach ($keys as $key) {
$this->entityManager->remove($key);
}
$this->entityManager->flush();
return new Response();
}
}

View file

@ -14,6 +14,7 @@ final class WebAPIRoutes
$group->post('/keys/import/perform', ImportKeysRoute::class); $group->post('/keys/import/perform', ImportKeysRoute::class);
$group->post('/keys/list/create', CreateKeyListRoute::class); $group->post('/keys/list/create', CreateKeyListRoute::class);
$group->post('/keys/list/delete',DeleteKeyList::class);
$group->get('/share/search', SearchForUsers::class); $group->get('/share/search', SearchForUsers::class);
$group->post('/share/add', AddUserToList::class); $group->post('/share/add', AddUserToList::class);

View file

@ -45,5 +45,16 @@ $resource = $resources->getResource($resourceEntry);
<span class="h1">PROTOTYPE / POC</span> <span class="h1">PROTOTYPE / POC</span>
</div> </div>
<div class="position-fixed bottom-0 start-0 m-3 fs-6">
<a href="https://git.php.fail/neintonine/gamesshop/issues/new" class="nav-link text-muted mb-3">
<i class="fa-solid fa-bug fa-xl me-3"></i>
You found a bug? Please report it.
</a>
<a href="https://git.php.fail/neintonine/gamesshop" class="nav-link text-muted">
<i class="fa-brands fa-git-alt me-3 fa-xl"></i>
Interested to help? Checkout the git repository.
</a>
</div>
</body> </body>
</html> </html>

View file

@ -29,17 +29,13 @@ $currentPermission = $activeUser === null ? UserPermission::NONE : $activeUser->
} }
?> ?>
<li class="nav-link"> <li class="nav-link">
<a href="<?= $header->link ?>" class="nav-link"><?= $header->title ?></a> <a href="<?= $header->link ?>" class="nav-link"><?= $header->title ?></a>
</li> </li>
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>
<?= $this->insert('layout/accountDisplay'); ?> <div class="d-flex mode-switch me-4">
</div>
</div>
<div class="d-flex mode-switch me-3">
<button title="Use dark mode" id="dark" class="btn btn-sm btn-default text-secondary"> <button title="Use dark mode" id="dark" class="btn btn-sm btn-default text-secondary">
<i class="fa-regular fa-moon"></i> <i class="fa-regular fa-moon"></i>
</button> </button>
@ -50,4 +46,7 @@ $currentPermission = $activeUser === null ? UserPermission::NONE : $activeUser->
<i class="fa-solid fa-display"></i> <i class="fa-solid fa-display"></i>
</button> </button>
</div> </div>
<?= $this->insert('layout/accountDisplay'); ?>
</div>
</div>
</nav> </nav>

View file

@ -19,12 +19,17 @@ $this->layout('layout/main', [ 'resourceEntry' => 'keys' ]);
</div> </div>
<div class="col-sm-6 align-self-center"> <div class="col-sm-6 align-self-center">
<?php if (!empty($usersLists)): ?> <?php if (!empty($usersLists)): ?>
<select name="lists" id="list-select" class="form-select w-100"> <div class="input-group w-100">
<select name="lists" id="list-select" class="form-select">
<?php foreach ($usersLists as $list): ?> <?php foreach ($usersLists as $list): ?>
<option value="<?= $list->getId() ?>"><?= $list->getName() ?></option> <option value="<?= $list->getId() ?>"><?= $list->getName() ?></option>
<?php endforeach; ?> <?php endforeach; ?>
<option value="_create">+ Create New</option> <option value="_create">+ Create New</option>
</select> </select>
<button class="btn btn-outline-secondary" data-bs-target="#edit-list-modal" data-bs-toggle="modal">
<i class="fa-solid fa-gear"></i>
</button>
</div>
<?php endif; ?> <?php endif; ?>
</div> </div>
</div> </div>
@ -151,4 +156,56 @@ $this->layout('layout/main', [ 'resourceEntry' => 'keys' ]);
</div> </div>
</div> </div>
<div class="modal" id="edit-list-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title h3">
Edit <span class="list-name"></span>
</h1>
</div>
<div class="modal-body">
<h2 class="h4 mt-2">
Actions
</h2>
<button data-bs-toggle="modal" data-bs-target="#delete-list-modal" class="w-100 btn btn-danger">Delete List</button>
</div>
<div class="modal-footer">
<button data-bs-dismiss="modal" class="flex-grow-1 btn btn-primary">
Save
</button>
</div>
</div>
</div>
</div>
<div class="modal" id="delete-list-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title h3">
Delete <span class="list-name"></span>?
</h1>
</div>
<div class="modal-body">
<p>
Are you <b>sure</b> you want to <b class="text-danger">delete</b> this list?
</p>
<p>
Deleting this will remove all the keys you added from the database.
</p>
</div>
<div class="modal-footer">
<button data-bs-dismiss="modal" class="flex-grow-1 btn btn-outline-primary">
Cancel
</button>
<button data-bs-dismiss="modal" class="js--yes flex-grow-1 btn btn-danger">
Yes
</button>
</div>
</div>
</div>
</div>
<?php $this->end() ?> <?php $this->end() ?>