snapshot of https://github.com/krayin/laravel-crm.git (2.2, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Admin | Playwright Tests / Admin | Playwright Tests | Shard 1 Of 6 (push) Failing after 37s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 2 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 4 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 6 Of 6 (push) Failing after 6s
Linting Tests / PHP 8.3 test on ubuntu-latest (push) Failing after 5s
CI / PHP 8.3 test on ubuntu-latest (push) Failing after 6s
Skills Consistency / validate-skills (push) Successful in 10s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 3 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 5 Of 6 (push) Failing after 6s
Some checks failed
Admin | Playwright Tests / Admin | Playwright Tests | Shard 1 Of 6 (push) Failing after 37s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 2 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 4 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 6 Of 6 (push) Failing after 6s
Linting Tests / PHP 8.3 test on ubuntu-latest (push) Failing after 5s
CI / PHP 8.3 test on ubuntu-latest (push) Failing after 6s
Skills Consistency / validate-skills (push) Successful in 10s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 3 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 5 Of 6 (push) Failing after 6s
This commit is contained in:
1
.ai/skills
Symbolic link
1
.ai/skills
Symbolic link
@@ -0,0 +1 @@
|
||||
../.github/skills
|
||||
1
.claude/skills
Symbolic link
1
.claude/skills
Symbolic link
@@ -0,0 +1 @@
|
||||
../.github/skills
|
||||
1
.codex/skills
Symbolic link
1
.codex/skills
Symbolic link
@@ -0,0 +1 @@
|
||||
../.github/skills
|
||||
1
.cursor/skills
Symbolic link
1
.cursor/skills
Symbolic link
@@ -0,0 +1 @@
|
||||
../.github/skills
|
||||
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{yml,yaml}]
|
||||
indent_size = 2
|
||||
71
.env.example
Normal file
71
.env.example
Normal file
@@ -0,0 +1,71 @@
|
||||
APP_NAME='Krayin CRM'
|
||||
APP_ENV=local
|
||||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
APP_TIMEZONE=Asia/Kolkata
|
||||
APP_LOCALE=en
|
||||
APP_CURRENCY=USD
|
||||
|
||||
VITE_HOST=
|
||||
VITE_PORT=
|
||||
|
||||
LOG_CHANNEL=stack
|
||||
LOG_LEVEL=debug
|
||||
|
||||
# Supported: mysql, mariadb
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=laravel-crm
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=
|
||||
DB_PREFIX=
|
||||
|
||||
BROADCAST_DRIVER=log
|
||||
CACHE_DRIVER=file
|
||||
QUEUE_CONNECTION=sync
|
||||
SESSION_DRIVER=file
|
||||
SESSION_LIFETIME=120
|
||||
|
||||
MEMCACHED_HOST=127.0.0.1
|
||||
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_PASSWORD=null
|
||||
REDIS_PORT=6379
|
||||
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=mailhog
|
||||
MAIL_PORT=1025
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_ENCRYPTION=null
|
||||
MAIL_FROM_ADDRESS=laravel@krayincrm.com
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
MAIL_DOMAIN=webkul.com
|
||||
|
||||
MAIL_RECEIVER_DRIVER=sendgrid
|
||||
|
||||
IMAP_HOST=imap.example.com
|
||||
IMAP_PORT=993
|
||||
IMAP_ENCRYPTION=ssl
|
||||
IMAP_VALIDATE_CERT=true
|
||||
IMAP_USERNAME=your_username
|
||||
IMAP_PASSWORD=your_password
|
||||
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
AWS_BUCKET=
|
||||
|
||||
GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
GOOGLE_REDIRECT_URI=
|
||||
|
||||
PUSHER_APP_ID=
|
||||
PUSHER_APP_KEY=
|
||||
PUSHER_APP_SECRET=
|
||||
PUSHER_APP_CLUSTER=mt1
|
||||
|
||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
* text=auto eol=lf
|
||||
|
||||
*.blade.php diff=html
|
||||
*.css diff=css
|
||||
*.html diff=html
|
||||
*.md diff=markdown
|
||||
*.php diff=php
|
||||
|
||||
/.github export-ignore
|
||||
CHANGELOG.md export-ignore
|
||||
.styleci.yml export-ignore
|
||||
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
open_collective: bagisto
|
||||
36
.github/ISSUE_TEMPLATE/1_Bug_report.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/1_Bug_report.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
name: "🐛 Bug Report"
|
||||
about: 'Report a general library issue.'
|
||||
---
|
||||
|
||||
# Bug report
|
||||
|
||||
### Title
|
||||
**Just a quick sentence to brief your trouble with Krayin CRM or something associated with it.**
|
||||
**Please be calm, short and emphasize on points.**
|
||||
|
||||
### Issue Description
|
||||
**Description helps the developers to understand the bug. It describes the problem encountered or some after effect of some kind.**
|
||||
|
||||
### Preconditions
|
||||
**Please provide as detailed information about your environment as possible.**
|
||||
|
||||
1. framework Version.
|
||||
2. Commit id.
|
||||
|
||||
### Steps to reproduce
|
||||
**It is important to provide a set of clear steps to reproduce this bug.If relevant please include code samples.**
|
||||
|
||||
1. step1
|
||||
2. step2
|
||||
|
||||
### Expected result
|
||||
**Tell us what should happen.**
|
||||
|
||||
* [Screenshots, logs or description]
|
||||
|
||||
### Actual result
|
||||
|
||||
> **Tell us what happens instead.**
|
||||
|
||||
* [points....]
|
||||
17
.github/ISSUE_TEMPLATE/2_Feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/2_Feature_request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: "💡 Feature Request"
|
||||
about: 'For ideas or feature requests, please make a pull request, or open an issue'
|
||||
---
|
||||
|
||||
This repository is only for reporting bugs or issues. If you need support, please use
|
||||
other channels:
|
||||
|
||||
1. Write an email - mailto:support@krayincrm.com
|
||||
|
||||
2. Create support ticket on https://krayincrm.uvdesk.com
|
||||
|
||||
3. Visit forums to get support from our community (https://forums.krayincrm.com)
|
||||
|
||||
Alternatively, you may use Facebook (https://www.facebook.com/groups/krayincrm/).
|
||||
|
||||
We promise that more channels are coming soon!!!
|
||||
11
.github/ISSUE_TEMPLATE/3_Support_question.md
vendored
Normal file
11
.github/ISSUE_TEMPLATE/3_Support_question.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
name: "❔ Support Question"
|
||||
about: 'This repository is only for reporting bugs or problems. If you need help, see:
|
||||
https://github.com/krayin/laravel-crm#documentation'
|
||||
---
|
||||
|
||||
This repository is only for reporting bugs or issues. If you need support, please use:
|
||||
|
||||
1. Create support ticket on https://krayincrm.uvdesk.com
|
||||
|
||||
Thanks!
|
||||
9
.github/ISSUE_TEMPLATE/4_Security_vulnerabilities.md
vendored
Normal file
9
.github/ISSUE_TEMPLATE/4_Security_vulnerabilities.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: "🔒 Security Vulnerabilities"
|
||||
about: 'For reporting security-related issues, see: https://github.com/krayin/laravel-crm#security-vulnerabilities'
|
||||
---
|
||||
|
||||
PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, SEE BELOW.
|
||||
|
||||
If you have security vulnerability to address related to Krayin then please write a mail to us:
|
||||
**support@krayincrm.com**
|
||||
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
## Issue Reference
|
||||
<!--- Please mention issue #id or use a comma if your pull request solves multiple issues. -->
|
||||
|
||||
## Description
|
||||
<!--- Please describe your changes in detail. -->
|
||||
|
||||
## How To Test This?
|
||||
<!--- Please describe in detail how to test the changes made in this pull request. -->
|
||||
|
||||
## Documentation
|
||||
- [ ] My pull request requires an update on the documentation repository.
|
||||
<!--- Please describe in detail what needs to be changed. --->
|
||||
|
||||
## Branch Selection
|
||||
<!--- Please specify the target branch for this pull request. -->
|
||||
- [ ] Target Branch: master
|
||||
|
||||
## Tailwind Reordering
|
||||
<!--- Please make sure all the Tailwind classes are reordered. -->
|
||||
51
.github/skills/README.md
vendored
Normal file
51
.github/skills/README.md
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# Skills Standard
|
||||
|
||||
## Canonical Source
|
||||
|
||||
All workspace skills are maintained in:
|
||||
|
||||
- `.github/skills/<skill-name>/SKILL.md`
|
||||
|
||||
This is the single source of truth for every AI coding agent in this repository.
|
||||
|
||||
## Agent Runtime Links
|
||||
|
||||
The following paths are **symlinks** to `.github/skills` so each agent runtime
|
||||
auto-discovers the same skills:
|
||||
|
||||
| Path | Agent |
|
||||
|------|-------|
|
||||
| `.ai/skills` | Generic / `.ai` convention |
|
||||
| `.claude/skills` | Claude Code |
|
||||
| `.codex/skills` | OpenAI Codex |
|
||||
| `.cursor/skills` | Cursor |
|
||||
| `.kilocode/skills` | Kilo Code |
|
||||
|
||||
> Symlinks are committed to git (mode `120000`). On a Windows checkout without
|
||||
> symlink support they may materialize as plain files — clone with symlink
|
||||
> support enabled (`git config core.symlinks true`).
|
||||
|
||||
## Available Skills
|
||||
|
||||
| Skill | Use when |
|
||||
|-------|----------|
|
||||
| `crm-package-development` | Creating a new Krayin CRM package/module or extending CRM functionality without touching core files. |
|
||||
| `pest-testing` | Writing or debugging Krayin CRM unit/feature tests with Pest. |
|
||||
|
||||
## Authoring Rules
|
||||
|
||||
- Add or update skills **only** in `.github/skills` (never edit through a symlink target name as if it were a separate copy).
|
||||
- Keep `name` and `description` in the YAML frontmatter of every `SKILL.md`.
|
||||
- `name` must be lowercase, hyphen-separated, and **match the skill's directory name**.
|
||||
- Use explicit "Use when..." trigger language in descriptions so agents match them reliably.
|
||||
- Do not maintain duplicate `SKILL.md` files in agent-specific folders.
|
||||
|
||||
## Validation
|
||||
|
||||
Validate frontmatter and naming with the Agent Skills reference tool:
|
||||
|
||||
```bash
|
||||
skills-ref validate .github/skills/<skill-name>
|
||||
```
|
||||
|
||||
See the [Agent Skills specification](https://agentskills.io/specification) for the full format.
|
||||
222
.github/skills/crm-package-development/SKILL.md
vendored
Normal file
222
.github/skills/crm-package-development/SKILL.md
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
---
|
||||
name: crm-package-development
|
||||
description: Use when creating a new Krayin CRM package or module, extending CRM functionality via a package, or adding custom business logic without modifying core files. Also use for any translation work — adding or moving lang files, adding a locale, or deciding whether a package gets its own Resources/lang directory — and whenever a fix or feature needs a CHANGELOG.md entry. Covers Laravel package structure, service providers, migrations, models, repositories, routes, controllers, views, localization, changelog entries, config, ACL, and menus.
|
||||
---
|
||||
|
||||
# Skill: CRM Package Development (Krayin CRM)
|
||||
|
||||
## Purpose
|
||||
This skill guides the AI agent to design and develop a new CRM package
|
||||
(module) for Krayin CRM in a clean, upgrade-safe, and maintainable way.
|
||||
|
||||
---
|
||||
|
||||
## When to Activate
|
||||
Activate this skill when the user wants to:
|
||||
- Create a new CRM package/module
|
||||
- Extend CRM functionality via a package
|
||||
- Add custom business logic without modifying core files
|
||||
- Add, move, or delete translation (lang) files, or add a new locale
|
||||
- Fix a bug or ship a feature — the change needs a `CHANGELOG.md` entry
|
||||
|
||||
---
|
||||
|
||||
## Project Context
|
||||
- Framework: Laravel
|
||||
- Product: Krayin CRM
|
||||
- Krayin CRM is already installed and running
|
||||
- The package must integrate seamlessly with existing CRM modules
|
||||
|
||||
---
|
||||
|
||||
## Development Rules
|
||||
- Follow Krayin CRM architecture and conventions
|
||||
- Do NOT modify core Krayin files unless explicitly required
|
||||
- Use Laravel package-based structure
|
||||
- All database changes must be done using migrations
|
||||
- Ensure backward compatibility and safe upgrades
|
||||
|
||||
---
|
||||
|
||||
## Package Structure Guidelines
|
||||
|
||||
A CRM package should follow this structure:
|
||||
|
||||
```text
|
||||
packages/
|
||||
└── Webkul/
|
||||
└── PackageName/
|
||||
├── src/
|
||||
│ ├── Providers/
|
||||
│ │ └── PackageServiceProvider.php
|
||||
│ ├── Models/
|
||||
│ ├── Contracts/
|
||||
│ ├── Repositories/
|
||||
│ ├── Http/
|
||||
│ │ ├── Controllers/
|
||||
│ │ └── Requests/
|
||||
│ ├── Routes/
|
||||
│ │ ├── admin.php
|
||||
│ │ └── api.php
|
||||
│ ├── Database/
|
||||
│ │ └── Migrations/
|
||||
│ ├── Resources/
|
||||
│ │ ├── views/ # only if the package renders its own Blade
|
||||
│ │ └── lang/ # ONLY if views/ exists — see Localization
|
||||
│ └── Config/
|
||||
│ ├── package.php
|
||||
│ ├── menu.php
|
||||
│ ├── core_config.php
|
||||
│ └── acl.php
|
||||
└── composer.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Localization (Translations)
|
||||
|
||||
### The rule
|
||||
|
||||
A package owns a `Resources/lang/` directory **only if it also owns
|
||||
`Resources/views/`** — that is, only if it renders its own Blade templates.
|
||||
Every other package ships **zero** translation files; its strings live in the
|
||||
**Admin** package under `admin::app.*`.
|
||||
|
||||
Before creating any lang file, ask:
|
||||
|
||||
> Does this package have `src/Resources/views/` with Blade templates?
|
||||
|
||||
- **Yes** → give it `Resources/lang/<locale>/app.php` and register its own
|
||||
namespace with `loadTranslationsFrom()` in the service provider.
|
||||
- **No** → do **not** create a lang directory and do **not** call
|
||||
`loadTranslationsFrom()`. Put the keys in the Admin package and reference them
|
||||
as `admin::app.…`.
|
||||
|
||||
Current state of the repo — preserve this invariant:
|
||||
|
||||
| Owns views | Packages | Translations live in |
|
||||
|---|---|---|
|
||||
| Yes | `Admin`, `Installer`, `WebForm` | the package itself (`admin::`, `installer::`, `web_form::`) |
|
||||
| No | everything else (`Core`, `DataTransfer`, `Lead`, `Contact`, `Quote`, `User`, …) | `Admin` (`admin::app.*`) |
|
||||
|
||||
"Backend-only" strings are still translations and follow the same rule —
|
||||
validation-rule messages, importer error maps, and `title` values referenced
|
||||
from `Config/*.php` all belong in Admin when the package has no views.
|
||||
|
||||
### Where keys go for a view-less package
|
||||
|
||||
Nest them under the Admin key that already owns that domain so one feature's
|
||||
strings stay together. Established precedent:
|
||||
|
||||
| Before | After |
|
||||
|---|---|
|
||||
| `core::app.validations.code` | `admin::app.validations.message.code` |
|
||||
| `data_transfer::app.importers.persons.title` | `admin::app.settings.data-transfer.importers.persons.title` |
|
||||
| `data_transfer::app.validation.errors.system` | `admin::app.settings.data-transfer.validation.errors.system` |
|
||||
|
||||
When you move keys out of a package, finish the job: rewrite every reference,
|
||||
delete the package's `Resources/lang/`, and remove its `loadTranslationsFrom()`
|
||||
call so the provider does not point at a path that no longer exists.
|
||||
|
||||
### Working with Admin lang files
|
||||
|
||||
- Admin ships one `app.php` per locale: `ar`, `en`, `es`, `fa`, `ko`, `pt_BR`,
|
||||
`tr`, `vi`, `zh_CN`. **Add every new key to all of them in the same change** —
|
||||
a key present only in `en` renders as the raw key string in other locales.
|
||||
- If a real translation is unavailable, use the English text as the value. Never
|
||||
omit the key, and never leave the key name as its own value.
|
||||
- Preserve placeholders exactly: `:attribute`, `:days`, `:count` (Laravel) and
|
||||
`%s` (importer messages formatted with `sprintf`).
|
||||
- Pint enforces a **single space** around `=>` (`pint.json` →
|
||||
`binary_operator_spaces`). Do not align `=>` into columns.
|
||||
- Name the file `app.php` in every locale directory. A misnamed file (e.g.
|
||||
`ar/ar.php`) is never loaded and the locale silently falls back to English.
|
||||
|
||||
### Adding a new locale
|
||||
|
||||
1. Create `<locale>/app.php` in each package that owns a lang directory
|
||||
(`Admin`, `Installer`, `WebForm`), mirroring the `en` key structure exactly.
|
||||
2. Register it in `config/app.php` → `available_locales`. This drives both the
|
||||
admin locale dropdown (via `Core@locales`) and the web installer.
|
||||
3. Add it to `$locales` in
|
||||
`packages/Webkul/Installer/src/Console/Commands/Installer.php` so the CLI
|
||||
installer offers it.
|
||||
4. If the script is right-to-left, add it to the `['fa', 'ar']` checks in the
|
||||
Admin layout Blade files.
|
||||
|
||||
### Verifying
|
||||
|
||||
Confirm parity with `en` — same key set, same placeholders — then check that
|
||||
keys actually resolve:
|
||||
|
||||
```bash
|
||||
php artisan tinker --execute='app()->setLocale("<locale>"); echo trans("admin::app.<your.key>");'
|
||||
./vendor/bin/pint --test packages/Webkul/<Package>
|
||||
```
|
||||
|
||||
A key that resolves to its own name (`admin::app.foo.bar`) is missing.
|
||||
|
||||
---
|
||||
|
||||
## Changelog
|
||||
|
||||
### The rule
|
||||
|
||||
**Every bug fix and every feature gets a `CHANGELOG.md` entry, in the same
|
||||
change.** Do not leave it for someone else and do not treat it as optional
|
||||
follow-up work — a fix that is not in the changelog is invisible to the release
|
||||
notes.
|
||||
|
||||
Add an entry when the change is user-visible or operator-visible: a bug fix, a
|
||||
new feature, an enhancement, a security fix, a configuration option, or a
|
||||
convention that affects how the product is built. Skip it only for changes with
|
||||
no observable effect at all — a typo in a code comment, a pure test refactor.
|
||||
|
||||
### Format
|
||||
|
||||
Entries live at the top of [CHANGELOG.md](../../../CHANGELOG.md), newest version
|
||||
first, and use exactly this shape:
|
||||
|
||||
```markdown
|
||||
## **v2.2.5 (Upcoming)**
|
||||
|
||||
* #2601[fixed] Fixed lead value not saved when the currency is changed.
|
||||
|
||||
* #2604[feature] Added Chinese (Simplified) translation.
|
||||
```
|
||||
|
||||
- One blank line between every entry — the file is read as rendered markdown.
|
||||
- No space between the issue number and the tag: `#2601[fixed]`, not `#2601 [fixed]`.
|
||||
- Write the description as a complete sentence ending in a period, phrased from
|
||||
the user's point of view, not the implementation's.
|
||||
|
||||
Valid tags, and when each applies:
|
||||
|
||||
| Tag | Use for |
|
||||
|---|---|
|
||||
| `[fixed]` | Something was broken and now works. |
|
||||
| `[feature]` | New capability that did not exist before. |
|
||||
| `[enhancement]` | Existing behaviour improved, refactored, or made faster. |
|
||||
| `[security]` | Vulnerability fix. Reference the CVE when one exists. |
|
||||
|
||||
### Which version section
|
||||
|
||||
Add to the topmost section if it is still unreleased. If the top section is
|
||||
already tagged `*Release*`, open a new one above it:
|
||||
|
||||
```markdown
|
||||
## **v<next patch version> (Upcoming)**
|
||||
```
|
||||
|
||||
Replace `(Upcoming)` with the real date in the release commit — the existing
|
||||
released headings show the expected style: `## **v2.2.4 (20th of July 2026)** *Release*`.
|
||||
|
||||
### Two things not to do
|
||||
|
||||
- **Never invent an issue or PR number.** They point at real GitHub PRs, so a
|
||||
guessed number creates a false reference. If the PR does not exist yet, omit
|
||||
the `#NNNN` prefix and leave the tag, then fill the number in once it is
|
||||
opened.
|
||||
- **Do not bump the version constant as part of a feature or fix.**
|
||||
`KRAYIN_VERSION` in `packages/Webkul/Core/src/Core.php` is incremented in the
|
||||
release commit, together with dating the changelog heading — not per change.
|
||||
144
.github/skills/pest-testing/SKILL.md
vendored
Normal file
144
.github/skills/pest-testing/SKILL.md
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
---
|
||||
name: pest-testing
|
||||
description: Use when writing or updating Krayin CRM tests (unit or feature), debugging test failures, using datasets, mocks or custom expectations, writing architecture tests, or when the user mentions test, spec, TDD, expects, assertion, or coverage. Uses the Pest PHP framework (v3) with Laravel 12.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: webkul
|
||||
---
|
||||
|
||||
# Pest Testing in Krayin CRM
|
||||
|
||||
## When to Apply
|
||||
|
||||
Activate this skill when:
|
||||
- Creating or updating tests (unit or feature)
|
||||
- Debugging test failures
|
||||
- Using datasets, mocks, or custom expectations
|
||||
- Writing architecture or convention tests
|
||||
- The user mentions test, spec, TDD, expects, assertion, coverage, or verifying behavior
|
||||
|
||||
## Krayin Testing Structure
|
||||
|
||||
### Test Locations
|
||||
|
||||
Krayin tests are stored in the root `tests/` directory:
|
||||
|
||||
```
|
||||
/tests
|
||||
├── Feature/
|
||||
├── Unit/
|
||||
├── Pest.php
|
||||
├── TestCase.php
|
||||
└── CreatesApplication.php
|
||||
```
|
||||
|
||||
### Available Test Suites
|
||||
|
||||
Defined in `phpunit.xml`:
|
||||
|
||||
| Test Suite | Location | Command |
|
||||
|------------|----------|---------|
|
||||
| Unit | `tests/Unit` | `php artisan test --testsuite="Unit"` |
|
||||
| Feature | `tests/Feature` | `php artisan test --testsuite="Feature"` |
|
||||
|
||||
## Pest.php Configuration
|
||||
|
||||
`tests/Pest.php` binds the base test case for feature tests:
|
||||
|
||||
```php
|
||||
uses(\Tests\TestCase::class)->in('Feature');
|
||||
```
|
||||
|
||||
It also defines helper functions you can reuse, such as:
|
||||
- `getDefaultAdmin()`
|
||||
- `actingAsSanctumAuthenticatedAdmin()`
|
||||
- `getFirstName($fullName)`
|
||||
|
||||
## Running Tests
|
||||
|
||||
### Run All Tests
|
||||
|
||||
```bash
|
||||
php artisan test --compact
|
||||
```
|
||||
|
||||
### Run a Specific Test Suite
|
||||
|
||||
```bash
|
||||
php artisan test --testsuite="Feature"
|
||||
php artisan test --testsuite="Unit"
|
||||
```
|
||||
|
||||
### Run a Specific Test File
|
||||
|
||||
```bash
|
||||
php artisan test --compact tests/Feature/ExampleTest.php
|
||||
```
|
||||
|
||||
### Run with Filter
|
||||
|
||||
```bash
|
||||
php artisan test --compact --filter=testName
|
||||
```
|
||||
|
||||
## Creating New Tests
|
||||
|
||||
### Create Feature Test
|
||||
|
||||
```bash
|
||||
php artisan make:test --pest ExampleFeatureTest
|
||||
```
|
||||
|
||||
### Create Unit Test
|
||||
|
||||
```bash
|
||||
php artisan make:test --pest --unit ExampleUnitTest
|
||||
```
|
||||
|
||||
## Basic Test Structure
|
||||
|
||||
```php
|
||||
it('passes basic assertion', function () {
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
|
||||
it('returns successful response', function () {
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertSuccessful();
|
||||
});
|
||||
```
|
||||
|
||||
## Assertions
|
||||
|
||||
Prefer specific response helpers:
|
||||
|
||||
| Use | Instead of |
|
||||
|-----|------------|
|
||||
| `assertSuccessful()` | `assertStatus(200)` |
|
||||
| `assertNotFound()` | `assertStatus(404)` |
|
||||
| `assertForbidden()` | `assertStatus(403)` |
|
||||
|
||||
## Datasets
|
||||
|
||||
```php
|
||||
it('has valid emails', function (string $email) {
|
||||
expect($email)->toContain('@');
|
||||
})->with([
|
||||
'james' => 'james@krayin.com',
|
||||
'john' => 'john@krayin.com',
|
||||
]);
|
||||
```
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- Forgetting to use `assertSuccessful()` and other specific helpers
|
||||
- Skipping `--pest` when creating tests
|
||||
- Ignoring helper utilities already available in `tests/Pest.php`
|
||||
|
||||
## Testing Best Practices
|
||||
|
||||
- Cover happy paths, failure paths, and edge cases
|
||||
- Keep tests isolated and focused
|
||||
- Use factories where available
|
||||
- Follow existing test patterns in the repository
|
||||
122
.github/workflows/admin_playwright_tests.yml
vendored
Normal file
122
.github/workflows/admin_playwright_tests.yml
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
name: Admin | Playwright Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
FORCE_COLOR: 1
|
||||
|
||||
jobs:
|
||||
admin_playwright_test:
|
||||
runs-on: ${{ matrix.operating-systems }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-systems: [ubuntu-latest]
|
||||
php-versions: ['8.3']
|
||||
node-version: ['22.13.1']
|
||||
shard-index: [1,2,3,4,5,6]
|
||||
shard-total: [6]
|
||||
|
||||
name: Admin | Playwright Tests | Shard ${{ matrix.shard-index }} Of ${{ matrix.shard-total }}
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: krayin
|
||||
ports:
|
||||
- 3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: curl, fileinfo, gd, intl, mbstring, openssl, pdo, pdo_mysql, tokenizer, zip
|
||||
ini-values: error_reporting=E_ALL
|
||||
tools: composer:v2
|
||||
|
||||
- name: Set Up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install Node.js Dependencies
|
||||
run: npm install
|
||||
working-directory: packages/Webkul/Admin
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
working-directory: packages/Webkul/Admin
|
||||
|
||||
- name: Setting Environment
|
||||
run: |
|
||||
cp .env.example .env
|
||||
sed -i "s|^\(DB_HOST=\s*\).*$|\1127.0.0.1|" .env
|
||||
sed -i "s|^\(DB_PORT=\s*\).*$|\1${{ job.services.mysql.ports['3306'] }}|" .env
|
||||
sed -i "s|^\(DB_DATABASE=\s*\).*$|\1krayin|" .env
|
||||
sed -i "s|^\(DB_USERNAME=\s*\).*$|\1root|" .env
|
||||
sed -i "s|^\(DB_PASSWORD=\s*\).*$|\1root|" .env
|
||||
sed -i "s|^\(APP_DEBUG=\s*\).*$|\1true|" .env
|
||||
sed -i "s|^\(APP_URL=\s*\).*$|\1http://127.0.0.1:8000|" .env
|
||||
cat .env
|
||||
|
||||
- name: Install Composer Dependencies
|
||||
run: composer install
|
||||
|
||||
- name: Running Krayin Installer
|
||||
run: php artisan krayin-crm:install --skip-env-check --skip-admin-creation
|
||||
|
||||
- name: Clear Laravel Caches
|
||||
run: php artisan optimize:clear
|
||||
|
||||
- name: Verify Activity Binding
|
||||
run: |
|
||||
php artisan tinker --execute="
|
||||
// 1) Laravel container binding (needed by repositories)
|
||||
if (! app()->bound(Webkul\\Activity\\Contracts\\Activity::class)) {
|
||||
throw new RuntimeException('Activity contract is NOT bound in Laravel container');
|
||||
}
|
||||
|
||||
// 2) Concord model-proxy registry (needed by ActivityProxy::modelClass())
|
||||
\$concord = app('concord');
|
||||
if (! \$concord->model(Webkul\\Activity\\Contracts\\Activity::class)) {
|
||||
throw new RuntimeException('Activity contract is NOT registered in Concord model registry');
|
||||
}
|
||||
|
||||
dump(app()->make(Webkul\\Activity\\Contracts\\Activity::class)::class);
|
||||
dump(\$concord->model(Webkul\\Activity\\Contracts\\Activity::class));
|
||||
"
|
||||
|
||||
# - name: Seed Product Table
|
||||
# run: php artisan db:seed --class="Webkul\\Installer\\Database\\Seeders\\ProductTableSeeder"
|
||||
|
||||
- name: Start Laravel server
|
||||
run: |
|
||||
php artisan serve --host=0.0.0.0 --port=8000 > server.log 2>&1 &
|
||||
echo "Waiting for server to start..."
|
||||
timeout 30 bash -c 'until curl -s http://127.0.0.1:8000 > /dev/null; do sleep 1; done'
|
||||
|
||||
- name: Run All Playwright Tests
|
||||
env:
|
||||
BASE_URL: 'http://127.0.0.1:8000'
|
||||
run: |
|
||||
npx playwright test --reporter=list --config=tests/e2e-pw/playwright.config.ts --shard=${{ matrix.shard-index }}/${{ matrix.shard-total }}
|
||||
working-directory: packages/Webkul/Admin
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: test-results-${{ matrix.shard-index }}-${{ github.run_id }}-${{ github.run_number }}
|
||||
path: packages/Webkul/Admin/tests/e2e-pw/test-results
|
||||
retention-days: 1
|
||||
40
.github/workflows/auto_commits.yml
vendored
Normal file
40
.github/workflows/auto_commits.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Linting Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
linting_tests:
|
||||
runs-on: ${{ matrix.operating-systems }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
operating-systems: [ubuntu-latest]
|
||||
php-versions: ['8.3']
|
||||
|
||||
name: PHP ${{ matrix.php-versions }} test on ${{ matrix.operating-systems }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: composer:v2
|
||||
|
||||
- name: Install Pint
|
||||
run: composer global require laravel/pint
|
||||
env:
|
||||
COMPOSER_HOME: ${{ runner.temp }}/composer
|
||||
|
||||
- name: Run Pint
|
||||
run: ${{ runner.temp }}/composer/vendor/bin/pint
|
||||
|
||||
- name: Commit Linted Files
|
||||
uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "chore: applied pint changes"
|
||||
55
.github/workflows/ci.yml
vendored
Normal file
55
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest]
|
||||
php-versions: ["8.3"]
|
||||
|
||||
name: PHP ${{ matrix.php-versions }} test on ${{ matrix.operating-system }}
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: krayin
|
||||
ports:
|
||||
- 3306
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: curl, gd, intl, mbstring, openssl, pdo, pdo_mysql, tokenizer, zip
|
||||
ini-values: error_reporting=E_ALL
|
||||
tools: composer:v2
|
||||
|
||||
- name: Running Composer Install
|
||||
run: composer install --no-interaction --prefer-dist --no-progress
|
||||
|
||||
- name: Set Testing Environment
|
||||
run: |
|
||||
cp .env.example .env
|
||||
sed -i "s|^\(APP_ENV=\s*\).*$|\1testing|" .env
|
||||
sed -i "s|^\(DB_HOST=\s*\).*$|\1127.0.0.1|" .env
|
||||
sed -i "s|^\(DB_PORT=\s*\).*$|\1${{ job.services.mysql.ports['3306'] }}|" .env
|
||||
sed -i "s|^\(DB_DATABASE=\s*\).*$|\1krayin|" .env
|
||||
sed -i "s|^\(DB_USERNAME=\s*\).*$|\1root|" .env
|
||||
sed -i "s|^\(DB_PASSWORD=\s*\).*$|\1root|" .env
|
||||
|
||||
- name: Running Krayin Installer
|
||||
run: php artisan krayin-crm:install --skip-env-check --skip-admin-creation
|
||||
|
||||
- name: Running Pest Test
|
||||
run: vendor/bin/pest --parallel --colors=always
|
||||
41
.github/workflows/skills-consistency.yml
vendored
Normal file
41
.github/workflows/skills-consistency.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Skills Consistency
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- '.github/skills/**'
|
||||
- '.ai/**'
|
||||
- '.claude/**'
|
||||
- '.codex/**'
|
||||
- '.cursor/**'
|
||||
- '.kilocode/**'
|
||||
- 'bin/validate-skills.sh'
|
||||
- '.github/workflows/skills-consistency.yml'
|
||||
push:
|
||||
branches:
|
||||
- '2.*'
|
||||
- master
|
||||
- main
|
||||
paths:
|
||||
- '.github/skills/**'
|
||||
- '.ai/**'
|
||||
- '.claude/**'
|
||||
- '.codex/**'
|
||||
- '.cursor/**'
|
||||
- '.kilocode/**'
|
||||
- 'bin/validate-skills.sh'
|
||||
- '.github/workflows/skills-consistency.yml'
|
||||
|
||||
jobs:
|
||||
validate-skills:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Validate skill source-of-truth
|
||||
run: bash bin/validate-skills.sh
|
||||
36
.gitignore
vendored
Normal file
36
.gitignore
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
.env
|
||||
.env.testing
|
||||
.idea
|
||||
.php_cs.cache
|
||||
.phpunit.result.cache
|
||||
.vscode
|
||||
.vagrant
|
||||
*.hot
|
||||
/stubs
|
||||
/data
|
||||
/docker-compose-collection
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
/ignorables/*
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
package-lock.json
|
||||
/docs
|
||||
/playwright-report
|
||||
/public/css
|
||||
/public/js
|
||||
/public/hot
|
||||
/public/storage
|
||||
/public/vendor
|
||||
/lang/vendor
|
||||
/storage/*.key
|
||||
/storage/dcc-data/
|
||||
/vendor
|
||||
yarn.lock
|
||||
yarn-error.log
|
||||
|
||||
# Playwright
|
||||
node_modules/
|
||||
/test-results/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
1
.kilocode/skills
Symbolic link
1
.kilocode/skills
Symbolic link
@@ -0,0 +1 @@
|
||||
../.github/skills
|
||||
9
.styleci.yml
Normal file
9
.styleci.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
php:
|
||||
preset: laravel
|
||||
disabled:
|
||||
- no_unused_imports
|
||||
finder:
|
||||
not-name:
|
||||
- index.php
|
||||
js: true
|
||||
css: true
|
||||
70
AGENTS.md
Normal file
70
AGENTS.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Krayin CRM: Agent Instructions
|
||||
|
||||
This repository ships reusable **agent skills** for developing Krayin CRM. These
|
||||
instructions apply to all AI coding agents (Claude Code, Codex, Copilot, Cursor,
|
||||
Kilo Code, etc.).
|
||||
|
||||
---
|
||||
|
||||
## Framework Context
|
||||
|
||||
- **Product:** Krayin CRM (Webkul) — an open-source Laravel CRM.
|
||||
- **Stack:** Laravel `^12.0`, PHP `^8.3`, Pest `^3.0`, Laravel Pint `^1.18`.
|
||||
- **Follow Krayin's own conventions** — use the patterns already present in this
|
||||
repository's modules; do not import patterns from other Laravel products.
|
||||
- **Module location:** `packages/Webkul/{ModuleName}/src/`
|
||||
- **Core modules (reference implementations):** `Lead`, `Contact`, `Activity`,
|
||||
`Quote`, `Product`, `User`, `Attribute`, `Core`, `Admin`, `DataGrid`.
|
||||
|
||||
---
|
||||
|
||||
## Skills
|
||||
|
||||
Workspace skills live in `.github/skills/` (canonical source) and are symlinked
|
||||
into every agent runtime (`.ai`, `.claude`, `.codex`, `.cursor`, `.kilocode`).
|
||||
See [.github/skills/README.md](.github/skills/README.md) for the standard.
|
||||
|
||||
| Skill | Use when |
|
||||
|-------|----------|
|
||||
| `crm-package-development` | Creating a new CRM package/module or extending CRM functionality without touching core. |
|
||||
| `pest-testing` | Writing or debugging unit/feature tests with Pest. |
|
||||
|
||||
Read the relevant `SKILL.md` before starting work in its domain. Do not restate
|
||||
skill content here — keep details in the skills.
|
||||
|
||||
---
|
||||
|
||||
## Critical Conventions (Never Deviate)
|
||||
|
||||
- **Never modify core Krayin files** unless explicitly required. Extend behavior
|
||||
through a package under `packages/Webkul/`.
|
||||
- **All schema changes go through migrations** — never edit the database directly.
|
||||
- **Follow the existing module layout** (Providers, Models, Contracts,
|
||||
Repositories, Http/Controllers, Routes, Database/Migrations, Resources/views,
|
||||
Config). The `crm-package-development` skill documents the full structure.
|
||||
- **Repository pattern:** models are accessed through repositories bound via
|
||||
contracts in the service provider — match the surrounding modules.
|
||||
- **Translations follow the views:** a package gets its own `Resources/lang/`
|
||||
**only if** it also has `Resources/views/`. Every view-less package keeps its
|
||||
strings in the Admin package under `admin::app.*` — no lang directory, no
|
||||
`loadTranslationsFrom()`. See the `crm-package-development` skill.
|
||||
- **Every fix and feature updates `CHANGELOG.md`** in the same change, under the
|
||||
topmost unreleased version heading. Never invent a `#PR` number and never bump
|
||||
`KRAYIN_VERSION` outside a release commit. See the `crm-package-development`
|
||||
skill for the entry format and tags.
|
||||
- **Preserve backward compatibility** so the CRM stays upgrade-safe.
|
||||
|
||||
---
|
||||
|
||||
## Development Cycle
|
||||
|
||||
```bash
|
||||
composer install # install PHP dependencies
|
||||
php artisan migrate # run migrations
|
||||
php artisan test --compact # run the Pest test suite
|
||||
./vendor/bin/pint # format code (PSR-12 via Laravel Pint)
|
||||
```
|
||||
|
||||
- Add tests for new behavior; follow the `pest-testing` skill.
|
||||
- Run `./vendor/bin/pint` before committing — CI applies Pint formatting.
|
||||
- Validate the skills setup with `bash bin/validate-skills.sh`.
|
||||
237
CHANGELOG.md
Executable file
237
CHANGELOG.md
Executable file
@@ -0,0 +1,237 @@
|
||||
# CHANGELOG for 2.2
|
||||
|
||||
This changelog consists of the bug & security fixes and new features being included in the releases listed below.
|
||||
|
||||
## **v2.2.6 (10th of Sept 2026)**
|
||||
|
||||
* [feature] Added MariaDB support.
|
||||
|
||||
* [feature] Added customizable lead card information. Datagrid columns and Kanban lead card fields can now be chosen per user through new column and card settings components.
|
||||
|
||||
* [feature] Added PDF export for dashboard reports, available from the dashboard alongside the existing views.
|
||||
|
||||
* [feature] Added Japanese (`ja`) translation for the Admin, Installer, GoogleContact and WebForm packages.
|
||||
|
||||
* [feature] Added an associated group column to the users grid in Settings > Users.
|
||||
|
||||
* [fixed] Fixed duplicated activity handling across the lead, person, product and warehouse activity controllers by consolidating the shared logic, and added the missing Japanese activity translations.
|
||||
|
||||
* [fixed] Fixed the data transfer import queue processing inconsistently, and corrected the form control group rendering used by the import screen.
|
||||
|
||||
* [fixed] Fixed the Google Contact settings screen erroring when no account was connected, and added the corresponding translations.
|
||||
|
||||
* [fixed] Fixed the mail ACL mapping so email actions are checked against the correct permission.
|
||||
|
||||
* [fixed] Fixed people created from a lead being saved with a null `user_id`, which hid them from the person listing for users restricted to group or individual data scope. They are now assigned to the lead owner, falling back to the acting user.
|
||||
|
||||
* [fixed] Fixed the stage API resource omitting `lead_pipeline_id`, so stages could not be matched to their pipeline.
|
||||
|
||||
* [fixed] Fixed email attachment downloads being blocked by the URL sanitizer middleware.
|
||||
|
||||
* [fixed] Added the missing Chinese translations for the users grid's associated group column.
|
||||
|
||||
* [fixed] Fixed flaky admin end-to-end tests around organization owner lookup, lead creation and rich-text comment fields.
|
||||
|
||||
* [security] Fixed user and role listings not being scoped by the acting user's data scope, which allowed users to see records outside their own group. Roles now track their creator via a new `created_by` column.
|
||||
|
||||
* [security] Hardened the admin ACL middleware to fail closed. An administrative route with no ACL mapping is now denied rather than allowed, inheriting the permission of its nearest mapped ancestor, with a narrow allow-list for authentication, self-service account management and generic UI helpers.
|
||||
|
||||
* [security] Removed SVG from the allowed upload types for the admin logo and favicon configuration fields.
|
||||
|
||||
* [security] Fixed a security issue configuration file uploads.
|
||||
|
||||
* [security] Fixed a security issue activity notes and the TinyMCE editor component.
|
||||
|
||||
* [security] Fixed a security issue in the web form embed view.
|
||||
|
||||
* [security] Fixed a security issue in attribute downloads.
|
||||
|
||||
* [security] Fixed a security issue in mail links.
|
||||
|
||||
* [security] Fixed broken tag handling in the tag settings controller.
|
||||
|
||||
* [security] Fixed SVG sanitization bypasses in media and configuration file uploads.
|
||||
|
||||
* [security] Secured installer APIs.
|
||||
|
||||
## **v2.2.5 (4th of Aug 2026)**
|
||||
|
||||
* #2631[fixed] Fixed the persons CSV import creating duplicate records and dropping select attribute values on re-import. Existing people are now updated by matched email regardless of a changed phone or organization (so the reported count is accurate), and select/multiselect option labels (or ids) are resolved to their option ids instead of being stored as `0`.
|
||||
|
||||
* #2630[fixed] Fixed date attributes in the persons CSV import silently saving as `0000-00-00`. Spreadsheet serial numbers and regional formats such as `DD/MM/YYYY` are now normalised to a valid date, and a value that cannot be parsed is reported as a row error instead of being stored as a zero date.
|
||||
|
||||
* [feature] Added Chinese (Simplified) `zh_CN` translation for the Admin, Installer, DataTransfer, WebForm and Core packages.
|
||||
|
||||
* [feature] Added a configurable default dashboard date range — 1 month, 3 months, 9 months, 1 year, 2 years or a custom number of days — under Configuration > General > Settings > Dashboard Configurations.
|
||||
|
||||
* [fixed] Fixed menu item names set in Configuration not applying to section pages, breadcrumbs and the mobile sidebar. Previously only the desktop sidebar reflected a rename.
|
||||
|
||||
* [fixed] Fixed renaming the "Mail" and "Contacts" menu items having no effect anywhere, as their configuration fields did not match the actual menu keys.
|
||||
|
||||
* [fixed] Fixed the dashboard date range label omitting the year on ranges spanning more than one calendar year, which rendered as "30 Jul - 30 Jul".
|
||||
|
||||
* [fixed] Fixed Arabic DataTransfer translations never loading, as the file was named `ar/ar.php` instead of `ar/app.php`.
|
||||
|
||||
* [fixed] Fixed the missing Korean translation for the "None" input validation option on the create and edit attribute forms.
|
||||
|
||||
* [enhancement] Moved the Core and DataTransfer package translations into the Admin package. Only packages that ship their own Blade views now carry a `Resources/lang` directory.
|
||||
|
||||
* [enhancement] Reduced database queries on every admin page by loading the configured menu names in a single query instead of one per menu item.
|
||||
|
||||
* [enhancement] Documented the localization convention in the `crm-package-development` agent skill and in AGENTS.md.
|
||||
* [feature] Added a collapse/expand toggle to the admin sidebar, matching the Bagisto admin. The choice is remembered across page loads, and page content now reflows to the sidebar width instead of being overlaid by it. The sidebar no longer expands on hover; it is controlled by the toggle only.
|
||||
* #2614[security] Fixed unauthenticated installer access and executable email attachment upload vulnerabilities.
|
||||
|
||||
* #2612[feature] Added import and export support for custom attributes for Leads and Persons.
|
||||
|
||||
* #2609[feature] Added Google Contacts export for Persons with Google account connection, duplicate detection, queued export progress, and result summary.
|
||||
|
||||
* #2608[fixed] Added missing "none" key to the Korean locale for attribute validation.
|
||||
|
||||
* #2606[feature] Added a collapse/expand toggle to the admin sidebar, matching the Bagisto admin. The choice is remembered across page loads, and page content now reflows to the sidebar width instead of being overlaid by it. The sidebar no longer expands on hover; it is controlled by the toggle only.
|
||||
|
||||
* #2606[feature] Added an option to show or hide the "Powered by" bar under Configuration > General > Settings > Powered by Section Configurations.
|
||||
|
||||
* #2603[feature] Added Korean translations for the Installer, DataTransfer, WebForm, and Core packages.
|
||||
|
||||
* #2602[feature] Added Korean translation support for the Admin package.
|
||||
|
||||
* #2600[fixed] Fixed invalid activity calendar .ics date-times by emitting UTC RFC 5545 values.
|
||||
|
||||
* #2592[security] Fixed webhook validation to reject internal endpoint URLs.
|
||||
|
||||
* #2580[enhancement] Added a "None" option to input validation for text attributes.
|
||||
|
||||
## **v2.2.4 (20th of July 2026)** *Release*
|
||||
|
||||
* #2590[fixed] Fixed page does not refresh after creating a record via Quick Add.
|
||||
|
||||
* #2589[fixed] Fixed Quick Add not working for users with group and individual permissions.
|
||||
|
||||
* #2582[fixed] Fixed pipeline field visible on public webform.
|
||||
|
||||
* #2581[enhancement] Fixed responsive UI issues when page is zoomed.
|
||||
|
||||
* #2579[feature] Allow group selection for individual view permission users.
|
||||
|
||||
* #2575[enhancement] Added previous month's sales update in Kanban view.
|
||||
|
||||
* #2573[enhancement] Added dashboard support for multiple pipelines.
|
||||
|
||||
* #2572[enhancement] Added filter by tag option in Contacts > Persons.
|
||||
|
||||
* #2571[fixed] Fixed issue with lead creation.
|
||||
|
||||
* #2570[fixed] Fixed auto-fill lead email issue.
|
||||
|
||||
* #2567[fixed] Fixed IDOR agent record access control vulnerability.
|
||||
|
||||
* #2563[fixed] Fixed Kanban infinite scroll duplicates issue.
|
||||
|
||||
* #2583[fixed] Fixed SQL injection in rotten lead filter.
|
||||
|
||||
* #2585[security] Fixed unrestricted file upload vulnerability (CVE-2026-38526).
|
||||
|
||||
* #2559[fixed] Fixed agent record access control issue.
|
||||
|
||||
* #2556[fixed] Fixed installation config save issue.
|
||||
|
||||
* #2550[fixed] Fixed Kanban infinite scroll duplicates.
|
||||
|
||||
* #2549[enhancement] Added support tab feature.
|
||||
|
||||
* #2548[enhancement] Allow search by phone and email when creating a lead.
|
||||
|
||||
* #2546[feature] Quick Attribute now available at lead form.
|
||||
|
||||
* #2545[feature] Added agent skills functionality.
|
||||
|
||||
* #2544[enhancement] Added validate skills.
|
||||
|
||||
* #2543[enhancement] Added Agents Skills folder.
|
||||
|
||||
* #2542[fixed] Fixed stored XSS vulnerability in notes field.
|
||||
|
||||
* #2541[fixed] Fixed quote description truncation issue.
|
||||
|
||||
* #2539[fixed] Fixed lost revenue arrow UI issue.
|
||||
|
||||
* #2538[fixed] Fixed missing translations.
|
||||
|
||||
* #2501[fixed] Fixed sales owner not saved in organization.
|
||||
|
||||
* #2500[fixed] Fixed activities date filter range issue.
|
||||
|
||||
* #2479[fixed] Fixed textarea field not rendered in WebForm.
|
||||
|
||||
* #2471[fixed] Fixed missing translations for lead won/lost modal.
|
||||
|
||||
* #2420[fixed] Added missing mega search translations for settings and configurations.
|
||||
|
||||
* #2533[fixed] Fixed GUI installation issue.
|
||||
|
||||
* #2419[security] Fixed stored XSS vulnerability in notes field.
|
||||
|
||||
* #2454[fixed] Fixed quote description truncation.
|
||||
|
||||
* #2407[fixed] Fixed missing translations.
|
||||
|
||||
* #2157[fixed] Fixed auto-fill lead email when creating a lead.
|
||||
|
||||
* #2258[fixed] Fixed issue with same-as-billing-address field.
|
||||
|
||||
## **v2.2.3 (1st of May 2026)** *Release*
|
||||
|
||||
* [fixed] Pipline critical issue resolved.
|
||||
|
||||
## **v2.2.2 (1st of May 2026)** *Release*
|
||||
|
||||
* [fixed] Update Change Log and version.
|
||||
|
||||
## **v2.2.1 (1st of May 2026)** *Release*
|
||||
|
||||
* [fixed] Quote fields now auto-fill correctly when a quote is linked to a lead.
|
||||
|
||||
* [fixed] Fixed price formatting issue.
|
||||
|
||||
* [fixed] Fixed Lead Kanban list ordering.
|
||||
|
||||
* [fixed] Fixed header block position at the top.
|
||||
|
||||
* [fixed] Updated Activity UI.
|
||||
|
||||
* [fixed] Admins can now view and share quote details to a person from the quote list.
|
||||
|
||||
* [fixed] Fixed submission issue on the web form.
|
||||
|
||||
* [fixed] Fixed activity display issue in the Calendar view.
|
||||
|
||||
* [fixed] Logo update issue resolved.
|
||||
|
||||
* [enhancement] Drag-and-drop support added to Activity. Admins can now change date and time directly from the Calendar view.
|
||||
|
||||
* [feature] Quick App feature added for faster access to key CRM actions.
|
||||
|
||||
* [feature] Admins can now add or update a person directly from the lead view page.
|
||||
|
||||
* [security] Resolved an authentication bypass vulnerability caused by improper access control in the installer.
|
||||
|
||||
## **v2.2.0 (17th of March 2026)** *Release*
|
||||
|
||||
* **[Laravel 12 Upgrade]** Upgraded framework to Laravel 12
|
||||
|
||||
* #2480[enhancement] Codebase updates and refinements.
|
||||
|
||||
* #2478[enhancement] Improved class instantiation handling.
|
||||
|
||||
* #2472[enhancement] Upgrade to Laravel 12.
|
||||
|
||||
* #2470[enhancement] Updated auto_commits.yml configuration.
|
||||
|
||||
* #2469[enhancement] General enhancements and optimizations.
|
||||
|
||||
* #2468[enhancement] Documentation updates (MD files).
|
||||
|
||||
* #2450[fixed] Added ACL support for warehouses.
|
||||
|
||||
* #2444[fixed] Improved global search functionality for organizations.
|
||||
76
CODE_OF_CONDUCT.md
Normal file
76
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at support@krayincrm.com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
20
LICENSE
Normal file
20
LICENSE
Normal file
@@ -0,0 +1,20 @@
|
||||
MIT License
|
||||
|
||||
Copyright 2010-2025, Webkul Software
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
152
README.md
Normal file
152
README.md
Normal file
@@ -0,0 +1,152 @@
|
||||
<p align="center">
|
||||
<a href="https://krayincrm.com">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" height="100" srcset="packages/Webkul/Admin/src/Resources/assets/images/dark-logo.svg">
|
||||
<source media="(prefers-color-scheme: light)" height="100" srcset="packages/Webkul/Admin/src/Resources/assets/images/logo.svg">
|
||||
<img alt="Krayin CRM" height="100" src="packages/Webkul/Admin/src/Resources/assets/images/logo.svg">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://packagist.org/packages/krayin/laravel-crm"><img src="https://poser.pugx.org/krayin/laravel-crm/d/total.svg" alt="Total Downloads"></a>
|
||||
<a href="https://packagist.org/packages/krayin/laravel-crm"><img src="https://poser.pugx.org/krayin/laravel-crm/v/stable.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/krayin/laravel-crm"><img src="https://poser.pugx.org/krayin/laravel-crm/license.svg" alt="License"></a>
|
||||
</p>
|
||||
|
||||
|
||||

|
||||
|
||||
## Topics
|
||||
|
||||
1. [Introduction](#introduction)
|
||||
2. [Documentation](#documentation)
|
||||
3. [Requirements](#requirements)
|
||||
4. [Installation & Configuration](#installation-and-configuration)
|
||||
4. [Docker Installation](https://devdocs.krayincrm.com/2.0/introduction/docker.html)
|
||||
5. [Krayin Cloud System](#krayin-cloud-hosting)
|
||||
6. [License](#license)
|
||||
7. [Security Vulnerabilities](#security-vulnerabilities)
|
||||
|
||||
### Introduction
|
||||
|
||||
[Krayin CRM](https://krayincrm.com) is a hand tailored CRM framework built on some of the hottest opensource technologies
|
||||
such as [Laravel](https://laravel.com) (a [PHP](https://secure.php.net/) framework) and [Vue.js](https://vuejs.org)
|
||||
a progressive Javascript framework.
|
||||
|
||||
**Free & Opensource Laravel CRM solution for SMEs and Enterprises for complete customer lifecycle management.**
|
||||
|
||||
**Read our documentation: [Krayin CRM Docs](https://devdocs.krayincrm.com/)**
|
||||
|
||||
**We also have a forum for any type of concerns, feature requests, or discussions. Please visit: [Krayin CRM Forums](https://forums.krayincrm.com/)**
|
||||
|
||||
# Visit our live [Demo](https://demo.krayincrm.com)
|
||||
|
||||
<a href="javascript:void();">
|
||||
<img class="flag-img" src="https://raw.githubusercontent.com/krayin/temp-media/master/visit-our-live-demo.png" alt="Chinese" width="100%">
|
||||
</a>
|
||||
|
||||
It packs in lots of features that will allow your E-Commerce business to scale in no time:
|
||||
|
||||
- Descriptive and Simple Admin Panel.
|
||||
- Admin Dashboard.
|
||||
- Custom Attributes.
|
||||
- Built on Modular Approach.
|
||||
- Email parsing via Sendgrid.
|
||||
- Check out [these features and more](https://krayincrm.com/features/).
|
||||
|
||||
**For Developers**:
|
||||
Take advantage of two of the hottest frameworks used in this project -- Laravel and Vue.js -- both of which have been used in Krayin CRM.
|
||||
|
||||
### Documentation
|
||||
|
||||
#### Krayin Documentation [https://devdocs.krayincrm.com](https://devdocs.krayincrm.com)
|
||||
|
||||
### Requirements
|
||||
|
||||
- **SERVER**: Apache 2 or NGINX.
|
||||
- **RAM**: 3 GB or higher.
|
||||
- **PHP**: 8.3 or higher
|
||||
- **Composer**: 2.5 or higher
|
||||
- **For MySQL users**: 8.0.32 or higher.
|
||||
- **For MariaDB users**: 11.4 LTS or higher (11.8 LTS recommended).
|
||||
|
||||
### Installation and Configuration
|
||||
|
||||
##### Execute these commands below, in order
|
||||
|
||||
```
|
||||
composer create-project
|
||||
```
|
||||
|
||||
- Find **.env** file in root directory and change the **APP_URL** param to your **domain**.
|
||||
|
||||
- Also, Configure the **Mail** and **Database** parameters inside **.env** file.
|
||||
|
||||
```
|
||||
php artisan krayin-crm:install
|
||||
```
|
||||
|
||||
**To execute Krayin**:
|
||||
|
||||
##### On server:
|
||||
|
||||
Warning: Before going into production mode we recommend you uninstall developer dependencies.
|
||||
In order to do that, run the command below:
|
||||
|
||||
> composer install --no-dev
|
||||
|
||||
```
|
||||
Open the specified entry point in your hosts file in your browser or make an entry in hosts file if not done.
|
||||
```
|
||||
|
||||
##### On local:
|
||||
|
||||
```
|
||||
php artisan route:clear
|
||||
php artisan serve
|
||||
```
|
||||
|
||||
|
||||
**How to log in as admin:**
|
||||
|
||||
> _http(s)://example.com/admin/login_
|
||||
|
||||
```
|
||||
email:admin@example.com
|
||||
password:admin123
|
||||
```
|
||||
|
||||
### Krayin Cloud Hosting
|
||||
|
||||
[Krayin CRM Cloud Hosting](https://krayincrm.com/crm-cloud-hosting) is a fully managed hosting solution where our team sets up, secures, and configures your Krayin CRM on reliable infrastructure.
|
||||
|
||||
Get a ready-to-use CRM on your own domain, without manual installation or infrastructure complexity, and focus on growing your business while we handle the technology.
|
||||
|
||||

|
||||
|
||||
### Krayin CRM Multi Tenant SaaS
|
||||
|
||||
[Krayin CRM Multi Tenant SaaS](https://krayincrm.com/extensions/krayin-crm-multi-tenant-saas-extension/) Krayin Multitenant SaaS is a Laravel-based CRM solution that allows multiple businesses (tenants) to use a single application instance while keeping their data isolated and secure.
|
||||
|
||||

|
||||
|
||||
### WhatsApp CRM Integration
|
||||
|
||||
[Krayin CRM WhatsApp](https://krayincrm.com/extensions/krayin-crm-whatsapp-extension/) Extension enables the store administrator to generate leads via their WhatsApp number.
|
||||
|
||||

|
||||
|
||||
### VoIP CRM Integration
|
||||
|
||||
[Krayin CRM VoIP](https://krayincrm.com/extensions/krayin-crm-voip/) extension allows the user to make Trunk calls over a broadband Internet connection and the user can also perform Inbound routes.
|
||||
|
||||

|
||||
|
||||
### License
|
||||
|
||||
Krayin CRM is a fully open-source CRM framework which will always be free under the [MIT License](https://github.com/krayin/laravel-crm/blob/2.1/LICENSE).
|
||||
|
||||
### Security Vulnerabilities
|
||||
|
||||
Please don't disclose security vulnerabilities publicly. If you find any security vulnerability in Krayin CRM then please email us: sales@krayincrm.com.
|
||||
42
UPGRADE.md
Normal file
42
UPGRADE.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# UPGRADE Guide
|
||||
|
||||
- [Upgrading To v2.2 From v2.1](#upgrading-to-v22-from-v21)
|
||||
|
||||
## High Impact Changes
|
||||
|
||||
- [Laravel 12 Upgrade](#laravel-12-upgrade)
|
||||
|
||||
## Upgrading To v2.2 From v2.1
|
||||
|
||||
> [!NOTE]
|
||||
> We strive to document every potential breaking change. However, as some of these alterations occur in lesser-known sections of Krayin, only a fraction of them may impact your application.
|
||||
|
||||
### Updating Dependencies
|
||||
|
||||
**Impact Probability: High**
|
||||
|
||||
#### PHP 8.3 Required
|
||||
|
||||
Krayin CRM v2.2 now requires PHP 8.3 or greater.
|
||||
|
||||
### Laravel 12 Upgrade
|
||||
|
||||
**Impact Probability: High**
|
||||
|
||||
Krayin CRM v2.2 has been upgraded to Laravel 12, which introduces stricter type checking and modernized date/time handling.
|
||||
|
||||
#### Key Changes
|
||||
|
||||
- **Bootstrap**: `bootstrap/app.php` now uses the new `Application::configure()` builder pattern. Service providers are listed in `bootstrap/providers.php`.
|
||||
|
||||
- **Kernels Removed**: `app/Http/Kernel.php` and `app/Console/Kernel.php` are removed. Middleware and scheduling are configured in `bootstrap/app.php` and `routes/console.php` respectively.
|
||||
|
||||
- **Exception Handler Removed**: `app/Exceptions/Handler.php` is removed. Exception handling is configured in `bootstrap/app.php`.
|
||||
|
||||
- **Middleware Classes Removed**: Built-in middleware wrappers (EncryptCookies, VerifyCsrfToken, TrimStrings, TrustProxies, etc.) are removed. Customizations are now done via `bootstrap/app.php`.
|
||||
|
||||
- **Service Providers Simplified**: `AuthServiceProvider`, `EventServiceProvider`, `RouteServiceProvider`, and `BroadcastServiceProvider` are removed. Their logic is handled in `bootstrap/app.php` or `AppServiceProvider`.
|
||||
|
||||
- **Config**: `config/app.php` no longer contains `providers` or `aliases` arrays.
|
||||
|
||||
- **doctrine/dbal** dependency has been removed (native column modification in Laravel 12).
|
||||
8
app/Http/Controllers/Controller.php
Normal file
8
app/Http/Controllers/Controller.php
Normal file
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
48
app/Models/User.php
Normal file
48
app/Models/User.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Database\Factories\UserFactory;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
/** @use HasFactory<UserFactory> */
|
||||
use HasFactory, Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the attributes that should be cast.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
}
|
||||
}
|
||||
24
app/Providers/AppServiceProvider.php
Normal file
24
app/Providers/AppServiceProvider.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
15
artisan
Executable file
15
artisan
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
|
||||
define('LARAVEL_START', microtime(true));
|
||||
|
||||
// Register the Composer autoloader...
|
||||
require __DIR__.'/vendor/autoload.php';
|
||||
|
||||
// Bootstrap Laravel and handle the command...
|
||||
$status = (require_once __DIR__.'/bootstrap/app.php')
|
||||
->handleCommand(new ArgvInput);
|
||||
|
||||
exit($status);
|
||||
76
bin/validate-skills.sh
Executable file
76
bin/validate-skills.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
canonical_dir=".github/skills"
|
||||
|
||||
echo "[skills] validating canonical directory"
|
||||
if [[ ! -d "$canonical_dir" ]]; then
|
||||
echo "ERROR: $canonical_dir does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
skill_count=$(find "$canonical_dir" -mindepth 2 -maxdepth 2 -type f -name SKILL.md | wc -l | tr -d ' ')
|
||||
if [[ "$skill_count" -eq 0 ]]; then
|
||||
echo "ERROR: no SKILL.md files found under $canonical_dir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[skills] validating agent link targets"
|
||||
while IFS='|' read -r link_path expected_target; do
|
||||
[[ -z "$link_path" ]] && continue
|
||||
|
||||
if [[ ! -L "$link_path" ]]; then
|
||||
echo "ERROR: $link_path must be a symlink to $expected_target"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
actual_target=$(readlink "$link_path")
|
||||
if [[ "$actual_target" != "$expected_target" ]]; then
|
||||
echo "ERROR: $link_path points to $actual_target (expected $expected_target)"
|
||||
exit 1
|
||||
fi
|
||||
done <<'LINKS'
|
||||
.ai/skills|../.github/skills
|
||||
.claude/skills|../.github/skills
|
||||
.codex/skills|../.github/skills
|
||||
.cursor/skills|../.github/skills
|
||||
.kilocode/skills|../.github/skills
|
||||
LINKS
|
||||
|
||||
echo "[skills] checking for SKILL.md outside canonical source"
|
||||
mapfile -t outside_skills < <(
|
||||
find . \
|
||||
-path './.git' -prune -o \
|
||||
-path './vendor' -prune -o \
|
||||
-path './node_modules' -prune -o \
|
||||
-type f -name SKILL.md -print \
|
||||
| grep -v '^./.github/skills/' || true
|
||||
)
|
||||
|
||||
if (( ${#outside_skills[@]} > 0 )); then
|
||||
echo "ERROR: found SKILL.md files outside $canonical_dir"
|
||||
printf ' - %s\n' "${outside_skills[@]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[skills] validating frontmatter keys and name/directory match"
|
||||
while IFS= read -r skill_file; do
|
||||
if ! grep -qE '^name:' "$skill_file"; then
|
||||
echo "ERROR: missing name in $skill_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -qE '^description:' "$skill_file"; then
|
||||
echo "ERROR: missing description in $skill_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dir_name=$(basename "$(dirname "$skill_file")")
|
||||
name_value=$(grep -E '^name:' "$skill_file" | head -1 | sed -E 's/^name:[[:space:]]*//; s/[[:space:]]*$//')
|
||||
if [[ "$name_value" != "$dir_name" ]]; then
|
||||
echo "ERROR: name '$name_value' must match directory '$dir_name' in $skill_file"
|
||||
exit 1
|
||||
fi
|
||||
done < <(find "$canonical_dir" -mindepth 2 -maxdepth 2 -type f -name SKILL.md | sort)
|
||||
|
||||
echo "[skills] validation passed ($skill_count skills)"
|
||||
36
bootstrap/app.php
Executable file
36
bootstrap/app.php
Executable file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
|
||||
use Webkul\Installer\Http\Middleware\CanInstall;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
web: __DIR__.'/../routes/web.php',
|
||||
api: __DIR__.'/../routes/api.php',
|
||||
commands: __DIR__.'/../routes/console.php',
|
||||
channels: __DIR__.'/../routes/channels.php',
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware) {
|
||||
$middleware->append(CanInstall::class);
|
||||
|
||||
$middleware->encryptCookies(except: [
|
||||
'dark_mode',
|
||||
'sidebar_collapsed',
|
||||
]);
|
||||
|
||||
$middleware->validateCsrfTokens(except: [
|
||||
'admin/mail/inbound-parse',
|
||||
'admin/web-forms/forms/*',
|
||||
]);
|
||||
|
||||
$middleware->api(prepend: [
|
||||
EnsureFrontendRequestsAreStateful::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
//
|
||||
})->create();
|
||||
2
bootstrap/cache/.gitignore
vendored
Normal file
2
bootstrap/cache/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
64
bootstrap/providers.php
Normal file
64
bootstrap/providers.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use App\Providers\AppServiceProvider;
|
||||
use Barryvdh\DomPDF\ServiceProvider;
|
||||
use Konekt\Concord\ConcordServiceProvider;
|
||||
use Prettus\Repository\Providers\RepositoryServiceProvider;
|
||||
use Webkul\Activity\Providers\ActivityServiceProvider;
|
||||
use Webkul\Admin\Providers\AdminServiceProvider;
|
||||
use Webkul\Attribute\Providers\AttributeServiceProvider;
|
||||
use Webkul\Automation\Providers\WorkflowServiceProvider;
|
||||
use Webkul\Contact\Providers\ContactServiceProvider;
|
||||
use Webkul\Core\Providers\CoreServiceProvider;
|
||||
use Webkul\DataGrid\Providers\DataGridServiceProvider;
|
||||
use Webkul\DataTransfer\Providers\DataTransferServiceProvider;
|
||||
use Webkul\Email\Providers\EmailServiceProvider;
|
||||
use Webkul\EmailTemplate\Providers\EmailTemplateServiceProvider;
|
||||
use Webkul\GoogleContact\Providers\GoogleContactServiceProvider;
|
||||
use Webkul\Installer\Providers\InstallerServiceProvider;
|
||||
use Webkul\Lead\Providers\LeadServiceProvider;
|
||||
use Webkul\Marketing\Providers\MarketingServiceProvider;
|
||||
use Webkul\Product\Providers\ProductServiceProvider;
|
||||
use Webkul\Quote\Providers\QuoteServiceProvider;
|
||||
use Webkul\Tag\Providers\TagServiceProvider;
|
||||
use Webkul\User\Providers\UserServiceProvider;
|
||||
use Webkul\Warehouse\Providers\WarehouseServiceProvider;
|
||||
use Webkul\WebForm\Providers\WebFormServiceProvider;
|
||||
|
||||
return [
|
||||
/*
|
||||
* Package Service Providers...
|
||||
*/
|
||||
ServiceProvider::class,
|
||||
ConcordServiceProvider::class,
|
||||
RepositoryServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
*/
|
||||
AppServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Webkul Service Providers...
|
||||
*/
|
||||
ActivityServiceProvider::class,
|
||||
AdminServiceProvider::class,
|
||||
AttributeServiceProvider::class,
|
||||
WorkflowServiceProvider::class,
|
||||
ContactServiceProvider::class,
|
||||
CoreServiceProvider::class,
|
||||
DataGridServiceProvider::class,
|
||||
DataTransferServiceProvider::class,
|
||||
EmailTemplateServiceProvider::class,
|
||||
EmailServiceProvider::class,
|
||||
GoogleContactServiceProvider::class,
|
||||
MarketingServiceProvider::class,
|
||||
InstallerServiceProvider::class,
|
||||
LeadServiceProvider::class,
|
||||
ProductServiceProvider::class,
|
||||
QuoteServiceProvider::class,
|
||||
TagServiceProvider::class,
|
||||
UserServiceProvider::class,
|
||||
WarehouseServiceProvider::class,
|
||||
WebFormServiceProvider::class,
|
||||
];
|
||||
115
composer.json
Normal file
115
composer.json
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"name": "krayin/laravel-crm",
|
||||
"type": "project",
|
||||
"description": "Krayin CRM",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"laravel"
|
||||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.3",
|
||||
"barryvdh/laravel-dompdf": "^3.1",
|
||||
"diglactic/laravel-breadcrumbs": "^10.0",
|
||||
"enshrined/svg-sanitize": "^0.22.0",
|
||||
"google/apiclient": "^2.18",
|
||||
"guzzlehttp/guzzle": "^7.8",
|
||||
"khaled.alshamaa/ar-php": "^6.3",
|
||||
"konekt/concord": "^1.17",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^2.10",
|
||||
"laravel/ui": "^4.6",
|
||||
"league/fractal": "^0.21.0",
|
||||
"maatwebsite/excel": "^3.1",
|
||||
"phpoffice/phpspreadsheet": "^1.30.6",
|
||||
"mpdf/mpdf": "^8.2",
|
||||
"prettus/l5-repository": "^3.0",
|
||||
"smalot/pdfparser": "^2.11",
|
||||
"webklex/laravel-imap": "^6.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.14",
|
||||
"fakerphp/faker": "^1.23",
|
||||
"krayin/krayin-package-generator": "dev-master",
|
||||
"laravel/pint": "^1.18",
|
||||
"laravel/sail": "^1.38",
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.0",
|
||||
"pestphp/pest": "^3.0",
|
||||
"pestphp/pest-plugin-laravel": "^3.0",
|
||||
"phpunit/phpunit": "^11.0",
|
||||
"spatie/laravel-ignition": "^2.8"
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"platform": {
|
||||
"php": "8.3.30"
|
||||
},
|
||||
"preferred-install": "dist",
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": []
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/",
|
||||
"Webkul\\Activity\\": "packages/Webkul/Activity/src",
|
||||
"Webkul\\Admin\\": "packages/Webkul/Admin/src",
|
||||
"Webkul\\Attribute\\": "packages/Webkul/Attribute/src",
|
||||
"Webkul\\Contact\\": "packages/Webkul/Contact/src",
|
||||
"Webkul\\Core\\": "packages/Webkul/Core/src",
|
||||
"Webkul\\DataGrid\\": "packages/Webkul/DataGrid/src",
|
||||
"Webkul\\DataTransfer\\": "packages/Webkul/DataTransfer/src",
|
||||
"Webkul\\Email\\": "packages/Webkul/Email/src",
|
||||
"Webkul\\EmailTemplate\\": "packages/Webkul/EmailTemplate/src",
|
||||
"Webkul\\GoogleContact\\": "packages/Webkul/GoogleContact/src",
|
||||
"Webkul\\Marketing\\": "packages/Webkul/Marketing/src",
|
||||
"Webkul\\Installer\\": "packages/Webkul/Installer/src",
|
||||
"Webkul\\Lead\\": "packages/Webkul/Lead/src",
|
||||
"Webkul\\Product\\": "packages/Webkul/Product/src",
|
||||
"Webkul\\Quote\\": "packages/Webkul/Quote/src",
|
||||
"Webkul\\Tag\\": "packages/Webkul/Tag/src",
|
||||
"Webkul\\User\\": "packages/Webkul/User/src",
|
||||
"Webkul\\Warehouse\\": "packages/Webkul/Warehouse/src",
|
||||
"Webkul\\WebForm\\": "packages/Webkul/WebForm/src",
|
||||
"Webkul\\Automation\\": "packages/Webkul/Automation/src"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "packages/*/*",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true,
|
||||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi"
|
||||
]
|
||||
}
|
||||
}
|
||||
189
config/app.php
Normal file
189
config/app.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value is the name of your application. This value is used when the
|
||||
| framework needs to place the application's name in a notification or
|
||||
| any other location as required by the application or its packages.
|
||||
|
|
||||
*/
|
||||
|
||||
'name' => env('APP_NAME', 'Laravel'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Environment
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the "environment" your application is currently
|
||||
| running in. This may determine how you prefer to configure various
|
||||
| services the application utilizes. Set this in your ".env" file.
|
||||
|
|
||||
*/
|
||||
|
||||
'env' => env('APP_ENV', 'production'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Debug Mode
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When your application is in debug mode, detailed error messages with
|
||||
| stack traces will be shown on every error that occurs within your
|
||||
| application. If disabled, a simple generic error page is shown.
|
||||
|
|
||||
*/
|
||||
|
||||
'debug' => (bool) env('APP_DEBUG', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This URL is used by the console to properly generate URLs when using
|
||||
| the Artisan command line tool. You should set this to the root of
|
||||
| your application so that it is used when running Artisan tasks.
|
||||
|
|
||||
*/
|
||||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Admin URL
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This URL suffix is used to define the admin url for example
|
||||
| admin/ or backend/
|
||||
|
|
||||
*/
|
||||
|
||||
'admin_path' => env('APP_ADMIN_PATH', 'admin'),
|
||||
|
||||
'asset_url' => env('ASSET_URL'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default timezone for your application, which
|
||||
| will be used by the PHP date and date-time functions. We have gone
|
||||
| ahead and set this to a sensible default for you out of the box.
|
||||
|
|
||||
*/
|
||||
|
||||
'timezone' => env('APP_TIMEZONE', 'Asia/Kolkata'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Locale Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The application locale determines the default locale that will be used
|
||||
| by the translation service provider. You are free to set this value
|
||||
| to any of the locales which will be supported by the application.
|
||||
|
|
||||
*/
|
||||
|
||||
'locale' => env('APP_LOCALE', 'en'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available Locales Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The application available locale determines the supported locales
|
||||
| by application
|
||||
|
|
||||
*/
|
||||
|
||||
'available_locales' => [
|
||||
'ar' => 'Arabic',
|
||||
'en' => 'English',
|
||||
'es' => 'Español',
|
||||
'fa' => 'Persian',
|
||||
'ja' => '日本語',
|
||||
'ko' => '한국어',
|
||||
'pt_BR' => 'Portuguese',
|
||||
'tr' => 'Türkçe',
|
||||
'vi' => 'Vietnamese',
|
||||
'zh_CN' => '简体中文',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Fallback Locale
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The fallback locale determines the locale to use when the current one
|
||||
| is not available. You may change the value to correspond to any of
|
||||
| the language folders that are provided through your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'fallback_locale' => 'en',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Faker Locale
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This locale will be used by the Faker PHP library when generating fake
|
||||
| data for your database seeds. For example, this will be used to get
|
||||
| localized telephone numbers, street address information and more.
|
||||
|
|
||||
*/
|
||||
|
||||
'faker_locale' => 'en_US',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Base Currency Code
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the base currency code for your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'currency' => env('APP_CURRENCY', 'USD'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Encryption Key
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This key is used by the Illuminate encrypter service and should be set
|
||||
| to a random, 32 character string, otherwise these encrypted strings
|
||||
| will not be safe. Please do this before deploying an application!
|
||||
|
|
||||
*/
|
||||
|
||||
'key' => env('APP_KEY'),
|
||||
|
||||
'cipher' => 'AES-256-CBC',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Maintenance Mode Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These configuration options determine the driver used to determine and
|
||||
| manage Laravel's "maintenance mode" status. The "cache" driver will
|
||||
| allow maintenance mode to be controlled across multiple machines.
|
||||
|
|
||||
| Supported drivers: "file", "cache"
|
||||
|
|
||||
*/
|
||||
|
||||
'maintenance' => [
|
||||
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
|
||||
'store' => env('APP_MAINTENANCE_STORE', 'database'),
|
||||
],
|
||||
];
|
||||
107
config/auth.php
Normal file
107
config/auth.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
use Webkul\User\Models\User;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Defaults
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default authentication "guard" and password
|
||||
| reset options for your application. You may change these defaults
|
||||
| as required, but they're a perfect start for most applications.
|
||||
|
|
||||
*/
|
||||
|
||||
'defaults' => [
|
||||
'guard' => 'user',
|
||||
'passwords' => 'users',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Next, you may define every authentication guard for your application.
|
||||
| Of course, a great default configuration has been defined for you
|
||||
| here which uses session storage and the Eloquent user provider.
|
||||
|
|
||||
| All authentication drivers have a user provider. This defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| mechanisms used by this application to persist your user's data.
|
||||
|
|
||||
| Supported: "session", "token"
|
||||
|
|
||||
*/
|
||||
|
||||
'guards' => [
|
||||
'user' => [
|
||||
'driver' => 'session',
|
||||
'provider' => 'users',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| User Providers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| All authentication drivers have a user provider. This defines how the
|
||||
| users are actually retrieved out of your database or other storage
|
||||
| mechanisms used by this application to persist your user's data.
|
||||
|
|
||||
| If you have multiple user tables or models you may configure multiple
|
||||
| sources which represent each model / table. These sources may then
|
||||
| be assigned to any extra authentication guards you have defined.
|
||||
|
|
||||
| Supported: "database", "eloquent"
|
||||
|
|
||||
*/
|
||||
|
||||
'providers' => [
|
||||
'users' => [
|
||||
'driver' => 'eloquent',
|
||||
'model' => User::class,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Resetting Passwords
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You may specify multiple password reset configurations if you have more
|
||||
| than one user table or model in the application and you want to have
|
||||
| separate password reset settings based on the specific user types.
|
||||
|
|
||||
| The expire time is the number of minutes that the reset token should be
|
||||
| considered valid. This security feature keeps tokens short-lived so
|
||||
| they have less time to be guessed. You may change this as needed.
|
||||
|
|
||||
*/
|
||||
|
||||
'passwords' => [
|
||||
'users' => [
|
||||
'provider' => 'users',
|
||||
'table' => 'user_password_resets',
|
||||
'expire' => 60,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Confirmation Timeout
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define the amount of seconds before a password confirmation
|
||||
| times out and the user is prompted to re-enter their password via the
|
||||
| confirmation screen. By default, the timeout lasts for three hours.
|
||||
|
|
||||
*/
|
||||
|
||||
'password_timeout' => 10800,
|
||||
|
||||
];
|
||||
78
config/breadcrumbs.php
Normal file
78
config/breadcrumbs.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
use Diglactic\Breadcrumbs\Generator;
|
||||
use Diglactic\Breadcrumbs\Manager;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| View Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Choose a view to display when Breadcrumbs::render() is called.
|
||||
| Built in templates are:
|
||||
|
|
||||
| - 'breadcrumbs::bootstrap5' - Bootstrap 5
|
||||
| - 'breadcrumbs::bootstrap4' - Bootstrap 4
|
||||
| - 'breadcrumbs::bulma' - Bulma
|
||||
| - 'breadcrumbs::foundation6' - Foundation 6
|
||||
| - 'breadcrumbs::json-ld' - JSON-LD Structured Data
|
||||
| - 'breadcrumbs::materialize' - Materialize
|
||||
| - 'breadcrumbs::tailwind' - Tailwind CSS
|
||||
| - 'breadcrumbs::uikit' - UIkit
|
||||
|
|
||||
| Or a custom view, e.g. '_partials/breadcrumbs'.
|
||||
|
|
||||
*/
|
||||
|
||||
'view' => 'breadcrumbs::bootstrap5',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Breadcrumbs File(s)
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The file(s) where breadcrumbs are defined. e.g.
|
||||
|
|
||||
| - base_path('routes/breadcrumbs.php')
|
||||
| - glob(base_path('breadcrumbs/*.php'))
|
||||
|
|
||||
*/
|
||||
|
||||
'files' => base_path('routes/breadcrumbs.php'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Exceptions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Determine when to throw an exception.
|
||||
|
|
||||
*/
|
||||
|
||||
// When route-bound breadcrumbs are used but the current route doesn't have a name (UnnamedRouteException)
|
||||
'unnamed-route-exception' => true,
|
||||
|
||||
// When route-bound breadcrumbs are used and the matching breadcrumb doesn't exist (InvalidBreadcrumbException)
|
||||
'missing-route-bound-breadcrumb-exception' => true,
|
||||
|
||||
// When a named breadcrumb is used but doesn't exist (InvalidBreadcrumbException)
|
||||
'invalid-named-breadcrumb-exception' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Classes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Subclass the default classes for more advanced customisations.
|
||||
|
|
||||
*/
|
||||
|
||||
// Manager
|
||||
'manager-class' => Manager::class,
|
||||
|
||||
// Generator
|
||||
'generator-class' => Generator::class,
|
||||
|
||||
];
|
||||
64
config/broadcasting.php
Normal file
64
config/broadcasting.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Broadcaster
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default broadcaster that will be used by the
|
||||
| framework when an event needs to be broadcast. You may set this to
|
||||
| any of the connections defined in the "connections" array below.
|
||||
|
|
||||
| Supported: "pusher", "ably", "redis", "log", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('BROADCAST_DRIVER', 'null'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Broadcast Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of the broadcast connections that will be used
|
||||
| to broadcast events to other systems or over websockets. Samples of
|
||||
| each available type of connection are provided inside this array.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'pusher' => [
|
||||
'driver' => 'pusher',
|
||||
'key' => env('PUSHER_APP_KEY'),
|
||||
'secret' => env('PUSHER_APP_SECRET'),
|
||||
'app_id' => env('PUSHER_APP_ID'),
|
||||
'options' => [
|
||||
'cluster' => env('PUSHER_APP_CLUSTER'),
|
||||
'useTLS' => true,
|
||||
],
|
||||
],
|
||||
|
||||
'ably' => [
|
||||
'driver' => 'ably',
|
||||
'key' => env('ABLY_KEY'),
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => 'default',
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'driver' => 'log',
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'null',
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
106
config/cache.php
Normal file
106
config/cache.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default cache connection that gets used while
|
||||
| using this caching library. This connection is used when another is
|
||||
| not explicitly specified when executing a given caching function.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('CACHE_DRIVER', 'file'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Stores
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may define all of the cache "stores" for your application as
|
||||
| well as their drivers. You may even define multiple stores for the
|
||||
| same cache driver to group types of items stored in your caches.
|
||||
|
|
||||
| Supported drivers: "apc", "array", "database", "file",
|
||||
| "memcached", "redis", "dynamodb", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'stores' => [
|
||||
|
||||
'apc' => [
|
||||
'driver' => 'apc',
|
||||
],
|
||||
|
||||
'array' => [
|
||||
'driver' => 'array',
|
||||
'serialize' => false,
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'table' => 'cache',
|
||||
'connection' => null,
|
||||
'lock_connection' => null,
|
||||
],
|
||||
|
||||
'file' => [
|
||||
'driver' => 'file',
|
||||
'path' => storage_path('framework/cache/data'),
|
||||
],
|
||||
|
||||
'memcached' => [
|
||||
'driver' => 'memcached',
|
||||
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
|
||||
'sasl' => [
|
||||
env('MEMCACHED_USERNAME'),
|
||||
env('MEMCACHED_PASSWORD'),
|
||||
],
|
||||
'options' => [
|
||||
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
|
||||
],
|
||||
'servers' => [
|
||||
[
|
||||
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
|
||||
'port' => env('MEMCACHED_PORT', 11211),
|
||||
'weight' => 100,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => 'cache',
|
||||
'lock_connection' => 'default',
|
||||
],
|
||||
|
||||
'dynamodb' => [
|
||||
'driver' => 'dynamodb',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
|
||||
'endpoint' => env('DYNAMODB_ENDPOINT'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Key Prefix
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When utilizing a RAM based store such as APC or Memcached, there might
|
||||
| be other applications utilizing the same cache. So, we'll specify a
|
||||
| value to get prefixed to all our keys so we can avoid collisions.
|
||||
|
|
||||
*/
|
||||
|
||||
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
|
||||
|
||||
];
|
||||
41
config/concord.php
Normal file
41
config/concord.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Webkul\Admin\Providers\ModuleServiceProvider as AdminModuleServiceProvider;
|
||||
use Webkul\Attribute\Providers\ModuleServiceProvider as AttributeModuleServiceProvider;
|
||||
use Webkul\Automation\Providers\ModuleServiceProvider as AutomationModuleServiceProvider;
|
||||
use Webkul\Contact\Providers\ModuleServiceProvider as ContactModuleServiceProvider;
|
||||
use Webkul\Core\Providers\ModuleServiceProvider as CoreModuleServiceProvider;
|
||||
use Webkul\DataGrid\Providers\ModuleServiceProvider as DataGridModuleServiceProvider;
|
||||
use Webkul\DataTransfer\Providers\ModuleServiceProvider as DataTransferModuleServiceProvider;
|
||||
use Webkul\Email\Providers\ModuleServiceProvider as EmailModuleServiceProvider;
|
||||
use Webkul\EmailTemplate\Providers\ModuleServiceProvider as EmailTemplateModuleServiceProvider;
|
||||
use Webkul\Lead\Providers\ModuleServiceProvider as LeadModuleServiceProvider;
|
||||
use Webkul\Product\Providers\ModuleServiceProvider as ProductModuleServiceProvider;
|
||||
use Webkul\Quote\Providers\ModuleServiceProvider as QuoteModuleServiceProvider;
|
||||
use Webkul\Tag\Providers\ModuleServiceProvider as TagModuleServiceProvider;
|
||||
use Webkul\User\Providers\ModuleServiceProvider as UserModuleServiceProvider;
|
||||
use Webkul\Warehouse\Providers\ModuleServiceProvider as WarehouseModuleServiceProvider;
|
||||
use Webkul\WebForm\Providers\ModuleServiceProvider as WebFormModuleServiceProvider;
|
||||
|
||||
return [
|
||||
'modules' => [
|
||||
DataTransferModuleServiceProvider::class,
|
||||
AdminModuleServiceProvider::class,
|
||||
AttributeModuleServiceProvider::class,
|
||||
AutomationModuleServiceProvider::class,
|
||||
ContactModuleServiceProvider::class,
|
||||
CoreModuleServiceProvider::class,
|
||||
DataGridModuleServiceProvider::class,
|
||||
EmailTemplateModuleServiceProvider::class,
|
||||
EmailModuleServiceProvider::class,
|
||||
LeadModuleServiceProvider::class,
|
||||
ProductModuleServiceProvider::class,
|
||||
QuoteModuleServiceProvider::class,
|
||||
TagModuleServiceProvider::class,
|
||||
UserModuleServiceProvider::class,
|
||||
WarehouseModuleServiceProvider::class,
|
||||
WebFormModuleServiceProvider::class,
|
||||
],
|
||||
|
||||
'register_route_models' => true,
|
||||
];
|
||||
62
config/cors.php
Normal file
62
config/cors.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Laravel CORS Options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The allowed_methods and allowed_headers options are case-insensitive.
|
||||
|
|
||||
| You don't need to provide both allowed_origins and allowed_origins_patterns.
|
||||
| If one of the strings passed matches, it is considered a valid origin.
|
||||
|
|
||||
| If ['*'] is provided to allowed_methods, allowed_origins or allowed_headers
|
||||
| all methods / origins / headers are allowed.
|
||||
|
|
||||
*/
|
||||
|
||||
/*
|
||||
* You can enable CORS for 1 or multiple paths.
|
||||
* Example: ['api/*']
|
||||
*/
|
||||
'paths' => [
|
||||
'admin/web-forms/forms/*',
|
||||
],
|
||||
|
||||
/*
|
||||
* Matches the request method. `['*']` allows all methods.
|
||||
*/
|
||||
'allowed_methods' => ['*'],
|
||||
|
||||
/*
|
||||
* Matches the request origin. `['*']` allows all origins. Wildcards can be used, eg `*.mydomain.com`
|
||||
*/
|
||||
'allowed_origins' => ['*'],
|
||||
|
||||
/*
|
||||
* Patterns that can be used with `preg_match` to match the origin.
|
||||
*/
|
||||
'allowed_origins_patterns' => [],
|
||||
|
||||
/*
|
||||
* Sets the Access-Control-Allow-Headers response header. `['*']` allows all headers.
|
||||
*/
|
||||
'allowed_headers' => ['*'],
|
||||
|
||||
/*
|
||||
* Sets the Access-Control-Expose-Headers response header with these headers.
|
||||
*/
|
||||
'exposed_headers' => [],
|
||||
|
||||
/*
|
||||
* Sets the Access-Control-Max-Age response header when > 0.
|
||||
*/
|
||||
'max_age' => 0,
|
||||
|
||||
/*
|
||||
* Sets the Access-Control-Allow-Credentials header.
|
||||
*/
|
||||
'supports_credentials' => false,
|
||||
];
|
||||
166
config/database.php
Normal file
166
config/database.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Database Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify which of the database connections below you wish
|
||||
| to use as your default connection for all database work. Of course
|
||||
| you may use many connections at once using the Database library.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('DB_CONNECTION', 'mysql'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Database Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here are each of the database connections setup for your application.
|
||||
| Of course, examples of configuring each database platform that is
|
||||
| supported by Laravel is shown below to make development simple.
|
||||
|
|
||||
|
|
||||
| All database work in Laravel is done through the PHP PDO facilities
|
||||
| so make sure you have the driver for your particular database of
|
||||
| choice installed on your machine before you begin development.
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sqlite' => [
|
||||
'driver' => 'sqlite',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'database' => env('DB_DATABASE', database_path('database.sqlite')),
|
||||
'prefix' => env('DB_PREFIX', ''),
|
||||
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
|
||||
],
|
||||
|
||||
'mysql' => [
|
||||
'driver' => 'mysql',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'forge'),
|
||||
'username' => env('DB_USERNAME', 'forge'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => env('DB_PREFIX', ''),
|
||||
'prefix_indexes' => true,
|
||||
'strict' => false,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'mariadb' => [
|
||||
'driver' => 'mariadb',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '3306'),
|
||||
'database' => env('DB_DATABASE', 'forge'),
|
||||
'username' => env('DB_USERNAME', 'forge'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'unix_socket' => env('DB_SOCKET', ''),
|
||||
'charset' => 'utf8mb4',
|
||||
'collation' => 'utf8mb4_unicode_ci',
|
||||
'prefix' => env('DB_PREFIX', ''),
|
||||
'prefix_indexes' => true,
|
||||
'strict' => false,
|
||||
'engine' => null,
|
||||
'options' => extension_loaded('pdo_mysql') ? array_filter([
|
||||
PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
|
||||
]) : [],
|
||||
],
|
||||
|
||||
'pgsql' => [
|
||||
'driver' => 'pgsql',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', '127.0.0.1'),
|
||||
'port' => env('DB_PORT', '5432'),
|
||||
'database' => env('DB_DATABASE', 'forge'),
|
||||
'username' => env('DB_USERNAME', 'forge'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => 'utf8',
|
||||
'prefix' => env('DB_PREFIX', ''),
|
||||
'prefix_indexes' => true,
|
||||
'schema' => 'public',
|
||||
'sslmode' => 'prefer',
|
||||
],
|
||||
|
||||
'sqlsrv' => [
|
||||
'driver' => 'sqlsrv',
|
||||
'url' => env('DATABASE_URL'),
|
||||
'host' => env('DB_HOST', 'localhost'),
|
||||
'port' => env('DB_PORT', '1433'),
|
||||
'database' => env('DB_DATABASE', 'forge'),
|
||||
'username' => env('DB_USERNAME', 'forge'),
|
||||
'password' => env('DB_PASSWORD', ''),
|
||||
'charset' => 'utf8',
|
||||
'prefix' => env('DB_PREFIX', ''),
|
||||
'prefix_indexes' => true,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Migration Repository Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This table keeps track of all the migrations that have already run for
|
||||
| your application. Using this information, we can determine which of
|
||||
| the migrations on disk haven't actually been run in the database.
|
||||
|
|
||||
*/
|
||||
|
||||
'migrations' => 'migrations',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Redis Databases
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Redis is an open source, fast, and advanced key-value store that also
|
||||
| provides a richer body of commands than a typical key-value system
|
||||
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
||||
|
|
||||
*/
|
||||
|
||||
'redis' => [
|
||||
|
||||
'client' => env('REDIS_CLIENT', 'phpredis'),
|
||||
|
||||
'options' => [
|
||||
'cluster' => env('REDIS_CLUSTER', 'redis'),
|
||||
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
|
||||
],
|
||||
|
||||
'default' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_DB', '0'),
|
||||
],
|
||||
|
||||
'cache' => [
|
||||
'url' => env('REDIS_URL'),
|
||||
'host' => env('REDIS_HOST', '127.0.0.1'),
|
||||
'password' => env('REDIS_PASSWORD', null),
|
||||
'port' => env('REDIS_PORT', '6379'),
|
||||
'database' => env('REDIS_CACHE_DB', '1'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
72
config/filesystems.php
Normal file
72
config/filesystems.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Filesystem Disk
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the default filesystem disk that should be used
|
||||
| by the framework. The "local" disk, as well as a variety of cloud
|
||||
| based disks are available to your application. Just store away!
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('FILESYSTEM_DISK', 'public'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Filesystem Disks
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure as many filesystem "disks" as you wish, and you
|
||||
| may even configure multiple disks of the same driver. Defaults have
|
||||
| been setup for each driver as an example of the required options.
|
||||
|
|
||||
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
||||
|
|
||||
*/
|
||||
|
||||
'disks' => [
|
||||
|
||||
'local' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app'),
|
||||
],
|
||||
|
||||
'public' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/public'),
|
||||
'url' => env('APP_URL').'/storage',
|
||||
'visibility' => 'public',
|
||||
],
|
||||
|
||||
's3' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION'),
|
||||
'bucket' => env('AWS_BUCKET'),
|
||||
'url' => env('AWS_URL'),
|
||||
'endpoint' => env('AWS_ENDPOINT'),
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Symbolic Links
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the symbolic links that will be created when the
|
||||
| `storage:link` Artisan command is executed. The array keys should be
|
||||
| the locations of the links and the values should be their targets.
|
||||
|
|
||||
*/
|
||||
|
||||
'links' => [
|
||||
public_path('storage') => storage_path('app/public'),
|
||||
],
|
||||
|
||||
];
|
||||
52
config/hashing.php
Normal file
52
config/hashing.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Hash Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default hash driver that will be used to hash
|
||||
| passwords for your application. By default, the bcrypt algorithm is
|
||||
| used; however, you remain free to modify this option if you wish.
|
||||
|
|
||||
| Supported: "bcrypt", "argon", "argon2id"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => 'bcrypt',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Bcrypt Options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the configuration options that should be used when
|
||||
| passwords are hashed using the Bcrypt algorithm. This will allow you
|
||||
| to control the amount of time it takes to hash the given password.
|
||||
|
|
||||
*/
|
||||
|
||||
'bcrypt' => [
|
||||
'rounds' => env('BCRYPT_ROUNDS', 10),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Argon Options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the configuration options that should be used when
|
||||
| passwords are hashed using the Argon algorithm. These will allow you
|
||||
| to control the amount of time it takes to hash the given password.
|
||||
|
|
||||
*/
|
||||
|
||||
'argon' => [
|
||||
'memory' => 1024,
|
||||
'threads' => 2,
|
||||
'time' => 2,
|
||||
],
|
||||
|
||||
];
|
||||
207
config/imap.php
Normal file
207
config/imap.php
Normal file
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
use Webklex\IMAP\Events\FlagDeletedEvent;
|
||||
use Webklex\IMAP\Events\FlagNewEvent;
|
||||
use Webklex\IMAP\Events\FolderDeletedEvent;
|
||||
use Webklex\IMAP\Events\FolderMovedEvent;
|
||||
use Webklex\IMAP\Events\FolderNewEvent;
|
||||
use Webklex\IMAP\Events\MessageCopiedEvent;
|
||||
use Webklex\IMAP\Events\MessageDeletedEvent;
|
||||
use Webklex\IMAP\Events\MessageMovedEvent;
|
||||
use Webklex\IMAP\Events\MessageNewEvent;
|
||||
use Webklex\IMAP\Events\MessageRestoredEvent;
|
||||
use Webklex\PHPIMAP\IMAP;
|
||||
use Webklex\PHPIMAP\Support\Masks\AttachmentMask;
|
||||
use Webklex\PHPIMAP\Support\Masks\MessageMask;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| IMAP default account
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default account identifier. It will be used as default for any missing account parameters.
|
||||
| If however the default account is missing a parameter the package default will be used.
|
||||
| Set to 'false' [boolean] to disable this functionality.
|
||||
|
|
||||
*/
|
||||
'default' => env('IMAP_DEFAULT_ACCOUNT', 'default'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default date format
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The default date format is used to convert any given Carbon::class object into a valid date string.
|
||||
| These are currently known working formats: "d-M-Y", "d-M-y", "d M y"
|
||||
|
|
||||
*/
|
||||
'date_format' => 'd-M-Y',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available IMAP accounts
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Please list all IMAP accounts which you are planning to use within the
|
||||
| array below.
|
||||
|
|
||||
*/
|
||||
'accounts' => [
|
||||
'default' => [
|
||||
'host' => env('IMAP_HOST', 'localhost'),
|
||||
'port' => env('IMAP_PORT', 993),
|
||||
'protocol' => env('IMAP_PROTOCOL', 'imap'), // might also use imap, [pop3 or nntp (untested)]
|
||||
'encryption' => env('IMAP_ENCRYPTION', 'ssl'), // Supported: false, 'ssl', 'tls', 'notls', 'starttls'
|
||||
'validate_cert' => env('IMAP_VALIDATE_CERT', true),
|
||||
'username' => env('IMAP_USERNAME', 'root@example.com'),
|
||||
'password' => env('IMAP_PASSWORD', ''),
|
||||
'authentication' => env('IMAP_AUTHENTICATION', null),
|
||||
'proxy' => [
|
||||
'socket' => null,
|
||||
'request_fulluri' => false,
|
||||
'username' => null,
|
||||
'password' => null,
|
||||
],
|
||||
'timeout' => 30,
|
||||
'extensions' => [],
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available IMAP options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Available php imap config parameters are listed below
|
||||
| -Delimiter (optional):
|
||||
| This option is only used when calling $oClient->
|
||||
| You can use any supported char such as ".", "/", (...)
|
||||
| -Fetch option:
|
||||
| IMAP::FT_UID - Message marked as read by fetching the body message
|
||||
| IMAP::FT_PEEK - Fetch the message without setting the "seen" flag
|
||||
| -Fetch sequence id:
|
||||
| IMAP::ST_UID - Fetch message components using the message uid
|
||||
| IMAP::ST_MSGN - Fetch message components using the message number
|
||||
| -Body download option
|
||||
| Default TRUE
|
||||
| -Flag download option
|
||||
| Default TRUE
|
||||
| -Soft fail
|
||||
| Default FALSE - Set to TRUE if you want to ignore certain exception while fetching bulk messages
|
||||
| -RFC822
|
||||
| Default TRUE - Set to FALSE to prevent the usage of \imap_rfc822_parse_headers().
|
||||
| See https://github.com/Webklex/php-imap/issues/115 for more information.
|
||||
| -Debug enable to trace communication traffic
|
||||
| -UID cache enable the UID cache
|
||||
| -Fallback date is used if the given message date could not be parsed
|
||||
| -Boundary regex used to detect message boundaries. If you are having problems with empty messages, missing
|
||||
| attachments or anything like this. Be advised that it likes to break which causes new problems..
|
||||
| -Message key identifier option
|
||||
| You can choose between the following:
|
||||
| 'id' - Use the MessageID as array key (default, might cause hickups with yahoo mail)
|
||||
| 'number' - Use the message number as array key (isn't always unique and can cause some interesting behavior)
|
||||
| 'list' - Use the message list number as array key (incrementing integer (does not always start at 0 or 1)
|
||||
| 'uid' - Use the message uid as array key (isn't always unique and can cause some interesting behavior)
|
||||
| -Fetch order
|
||||
| 'asc' - Order all messages ascending (probably results in oldest first)
|
||||
| 'desc' - Order all messages descending (probably results in newest first)
|
||||
| -Disposition types potentially considered an attachment
|
||||
| Default ['attachment', 'inline']
|
||||
| -Common folders
|
||||
| Default folder locations and paths assumed if none is provided
|
||||
| -Open IMAP options:
|
||||
| DISABLE_AUTHENTICATOR - Disable authentication properties.
|
||||
| Use 'GSSAPI' if you encounter the following
|
||||
| error: "Kerberos error: No credentials cache
|
||||
| file found (try running kinit) (...)"
|
||||
| or ['GSSAPI','PLAIN'] if you are using outlook mail
|
||||
| -Decoder options (currently only the message subject and attachment name decoder can be set)
|
||||
| 'utf-8' - Uses imap_utf8($string) to decode a string
|
||||
| 'mimeheader' - Uses mb_decode_mimeheader($string) to decode a string
|
||||
|
|
||||
*/
|
||||
'options' => [
|
||||
'delimiter' => '/',
|
||||
'fetch' => IMAP::FT_PEEK,
|
||||
'sequence' => IMAP::ST_UID,
|
||||
'fetch_body' => true,
|
||||
'fetch_flags' => true,
|
||||
'soft_fail' => false,
|
||||
'rfc822' => true,
|
||||
'debug' => false,
|
||||
'uid_cache' => true,
|
||||
// 'fallback_date' => "01.01.1970 00:00:00",
|
||||
'boundary' => '/boundary=(.*?(?=;)|(.*))/i',
|
||||
'message_key' => 'list',
|
||||
'fetch_order' => 'asc',
|
||||
'dispositions' => ['attachment', 'inline'],
|
||||
'common_folders' => [
|
||||
'root' => 'INBOX',
|
||||
'junk' => 'INBOX/Junk',
|
||||
'draft' => 'INBOX/Drafts',
|
||||
'sent' => 'INBOX/Sent',
|
||||
'trash' => 'INBOX/Trash',
|
||||
],
|
||||
'decoder' => [
|
||||
'message' => 'utf-8', // mimeheader
|
||||
'attachment' => 'utf-8', // mimeheader
|
||||
],
|
||||
'open' => [
|
||||
// 'DISABLE_AUTHENTICATOR' => 'GSSAPI'
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available flags
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| List all available / supported flags. Set to null to accept all given flags.
|
||||
*/
|
||||
'flags' => ['recent', 'flagged', 'answered', 'deleted', 'seen', 'draft'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available events
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
'events' => [
|
||||
'message' => [
|
||||
'new' => MessageNewEvent::class,
|
||||
'moved' => MessageMovedEvent::class,
|
||||
'copied' => MessageCopiedEvent::class,
|
||||
'deleted' => MessageDeletedEvent::class,
|
||||
'restored' => MessageRestoredEvent::class,
|
||||
],
|
||||
'folder' => [
|
||||
'new' => FolderNewEvent::class,
|
||||
'moved' => FolderMovedEvent::class,
|
||||
'deleted' => FolderDeletedEvent::class,
|
||||
],
|
||||
'flag' => [
|
||||
'new' => FlagNewEvent::class,
|
||||
'deleted' => FlagDeletedEvent::class,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Available masking options
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By using your own custom masks you can implement your own methods for
|
||||
| a better and faster access and less code to write.
|
||||
|
|
||||
| Checkout the two examples custom_attachment_mask and custom_message_mask
|
||||
| for a quick start.
|
||||
|
|
||||
| The provided masks below are used as the default masks.
|
||||
*/
|
||||
'masks' => [
|
||||
'message' => MessageMask::class,
|
||||
'attachment' => AttachmentMask::class,
|
||||
],
|
||||
];
|
||||
32
config/krayin-vite.php
Executable file
32
config/krayin-vite.php
Executable file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Krayin Vite Configuration
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Please add your Vite registry here to seamlessly support the `assets` function.
|
||||
|
|
||||
*/
|
||||
|
||||
'viters' => [
|
||||
'admin' => [
|
||||
'hot_file' => 'admin-vite.hot',
|
||||
'build_directory' => 'admin/build',
|
||||
'package_assets_directory' => 'src/Resources/assets',
|
||||
],
|
||||
|
||||
'installer' => [
|
||||
'hot_file' => 'installer-vite.hot',
|
||||
'build_directory' => 'installer/build',
|
||||
'package_assets_directory' => 'src/Resources/assets',
|
||||
],
|
||||
|
||||
'webform' => [
|
||||
'hot_file' => 'webform-vite.hot',
|
||||
'build_directory' => 'webform/build',
|
||||
'package_assets_directory' => 'src/Resources/assets',
|
||||
],
|
||||
],
|
||||
];
|
||||
104
config/logging.php
Normal file
104
config/logging.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
use Monolog\Handler\NullHandler;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\SyslogUdpHandler;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Log Channel
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option defines the default log channel that gets used when writing
|
||||
| messages to the logs. The name specified in this option should match
|
||||
| one of the channels defined in the "channels" configuration array.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('LOG_CHANNEL', 'stack'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Log Channels
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the log channels for your application. Out of
|
||||
| the box, Laravel uses the Monolog PHP logging library. This gives
|
||||
| you a variety of powerful log handlers / formatters to utilize.
|
||||
|
|
||||
| Available Drivers: "single", "daily", "slack", "syslog",
|
||||
| "errorlog", "monolog",
|
||||
| "custom", "stack"
|
||||
|
|
||||
*/
|
||||
|
||||
'channels' => [
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => ['single'],
|
||||
'ignore_exceptions' => false,
|
||||
],
|
||||
|
||||
'single' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
],
|
||||
|
||||
'daily' => [
|
||||
'driver' => 'daily',
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'days' => 14,
|
||||
],
|
||||
|
||||
'slack' => [
|
||||
'driver' => 'slack',
|
||||
'url' => env('LOG_SLACK_WEBHOOK_URL'),
|
||||
'username' => 'Laravel Log',
|
||||
'emoji' => ':boom:',
|
||||
'level' => env('LOG_LEVEL', 'critical'),
|
||||
],
|
||||
|
||||
'papertrail' => [
|
||||
'driver' => 'monolog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
'handler' => SyslogUdpHandler::class,
|
||||
'handler_with' => [
|
||||
'host' => env('PAPERTRAIL_URL'),
|
||||
'port' => env('PAPERTRAIL_PORT'),
|
||||
],
|
||||
],
|
||||
|
||||
'stderr' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => StreamHandler::class,
|
||||
'formatter' => env('LOG_STDERR_FORMATTER'),
|
||||
'with' => [
|
||||
'stream' => 'php://stderr',
|
||||
],
|
||||
],
|
||||
|
||||
'syslog' => [
|
||||
'driver' => 'syslog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
],
|
||||
|
||||
'errorlog' => [
|
||||
'driver' => 'errorlog',
|
||||
'level' => env('LOG_LEVEL', 'debug'),
|
||||
],
|
||||
|
||||
'null' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => NullHandler::class,
|
||||
],
|
||||
|
||||
'emergency' => [
|
||||
'path' => storage_path('logs/laravel.log'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
17
config/mail-receiver.php
Normal file
17
config/mail-receiver.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Mail Receiver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default mail receiver that is used to receive any email
|
||||
| messages sent by third party application.
|
||||
|
|
||||
| Supported: "webklex-imap", "sendgrid"
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('MAIL_RECEIVER_DRIVER', 'sendgrid'),
|
||||
];
|
||||
130
config/mail.php
Normal file
130
config/mail.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Mailer
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default mailer that is used to send any email
|
||||
| messages sent by your application. Alternative mailers may be setup
|
||||
| and used as needed; however, this mailer will be used by default.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('MAIL_MAILER', 'smtp'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mailer Configurations
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure all of the mailers used by your application plus
|
||||
| their respective settings. Several examples have been configured for
|
||||
| you and you are free to add your own as your application requires.
|
||||
|
|
||||
| Laravel supports a variety of mail "transport" drivers to be used while
|
||||
| sending an e-mail. You will specify which one you are using for your
|
||||
| mailers below. You are free to add additional mailers as required.
|
||||
|
|
||||
| Supported: "smtp", "sendmail", "mailgun", "ses",
|
||||
| "postmark", "log", "array", "failover"
|
||||
|
|
||||
*/
|
||||
|
||||
'mailers' => [
|
||||
'smtp' => [
|
||||
'transport' => 'smtp',
|
||||
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
|
||||
'port' => env('MAIL_PORT', 587),
|
||||
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
|
||||
'username' => env('MAIL_USERNAME'),
|
||||
'password' => env('MAIL_PASSWORD'),
|
||||
'timeout' => null,
|
||||
'verify_peer' => false,
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'transport' => 'ses',
|
||||
],
|
||||
|
||||
'mailgun' => [
|
||||
'transport' => 'mailgun',
|
||||
],
|
||||
|
||||
'postmark' => [
|
||||
'transport' => 'postmark',
|
||||
],
|
||||
|
||||
'sendmail' => [
|
||||
'transport' => 'sendmail',
|
||||
'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'),
|
||||
],
|
||||
|
||||
'log' => [
|
||||
'transport' => 'log',
|
||||
'channel' => env('MAIL_LOG_CHANNEL'),
|
||||
],
|
||||
|
||||
'array' => [
|
||||
'transport' => 'array',
|
||||
],
|
||||
|
||||
'failover' => [
|
||||
'transport' => 'failover',
|
||||
'mailers' => [
|
||||
'smtp',
|
||||
'log',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global "From" Address
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| You may wish for all e-mails sent by your application to be sent from
|
||||
| the same address. Here, you may specify a name and address that is
|
||||
| used globally for all e-mails that are sent by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'from' => [
|
||||
'address' => env('MAIL_FROM_ADDRESS'),
|
||||
'name' => env('MAIL_FROM_NAME'),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Mailer Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the domain for email message_id that is used to send email
|
||||
| messages sent by your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('MAIL_DOMAIN', 'webkul.com'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Markdown Mail Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| If you are using Markdown based email rendering, you may configure your
|
||||
| theme and component paths here, allowing you to customize the design
|
||||
| of the emails. Or, you may simply stick with the Laravel defaults!
|
||||
|
|
||||
*/
|
||||
|
||||
'markdown' => [
|
||||
'theme' => 'default',
|
||||
|
||||
'paths' => [
|
||||
resource_path('views/vendor/mail'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
89
config/queue.php
Normal file
89
config/queue.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Queue Connection Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Laravel's queue API supports an assortment of back-ends via a single
|
||||
| API, giving you convenient access to each back-end using the same
|
||||
| syntax for every one. Here you may define a default connection.
|
||||
|
|
||||
*/
|
||||
|
||||
'default' => env('QUEUE_CONNECTION', 'sync'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queue Connections
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may configure the connection information for each server that
|
||||
| is used by your application. A default configuration has been added
|
||||
| for each back-end shipped with Laravel. You are free to add more.
|
||||
|
|
||||
| Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
||||
|
|
||||
*/
|
||||
|
||||
'connections' => [
|
||||
|
||||
'sync' => [
|
||||
'driver' => 'sync',
|
||||
],
|
||||
|
||||
'database' => [
|
||||
'driver' => 'database',
|
||||
'table' => 'jobs',
|
||||
'queue' => 'default',
|
||||
'retry_after' => 90,
|
||||
],
|
||||
|
||||
'beanstalkd' => [
|
||||
'driver' => 'beanstalkd',
|
||||
'host' => 'localhost',
|
||||
'queue' => 'default',
|
||||
'retry_after' => 90,
|
||||
'block_for' => 0,
|
||||
],
|
||||
|
||||
'sqs' => [
|
||||
'driver' => 'sqs',
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
|
||||
'queue' => env('SQS_QUEUE', 'your-queue-name'),
|
||||
'suffix' => env('SQS_SUFFIX'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'redis' => [
|
||||
'driver' => 'redis',
|
||||
'connection' => 'default',
|
||||
'queue' => env('REDIS_QUEUE', 'default'),
|
||||
'retry_after' => 90,
|
||||
'block_for' => null,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Failed Queue Jobs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These options configure the behavior of failed queue job logging so you
|
||||
| can control which database and table are used to store the jobs that
|
||||
| have failed. You may change them to any database / table you wish.
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => [
|
||||
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
|
||||
'database' => env('DB_CONNECTION', 'mysql'),
|
||||
'table' => 'failed_jobs',
|
||||
],
|
||||
|
||||
];
|
||||
249
config/repository.php
Normal file
249
config/repository.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
use League\Fractal\Serializer\DataArraySerializer;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Prettus Repository Config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
|
|
||||
*/
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Repository Pagination Limit Default
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
'pagination' => [
|
||||
'limit' => 15,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Fractal Presenter Config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
|
||||
Available serializers:
|
||||
ArraySerializer
|
||||
DataArraySerializer
|
||||
JsonApiSerializer
|
||||
|
||||
*/
|
||||
'fractal' => [
|
||||
'params' => [
|
||||
'include' => 'include',
|
||||
],
|
||||
'serializer' => DataArraySerializer::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
'cache' => [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Status
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Enable or disable cache
|
||||
|
|
||||
*/
|
||||
'enabled' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Minutes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Time of expiration cache
|
||||
|
|
||||
*/
|
||||
'minutes' => 30,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Repository
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Instance of Illuminate\Contracts\Cache\Repository
|
||||
|
|
||||
*/
|
||||
'repository' => 'cache',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Cache Clean Listener
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
|
|
||||
|
|
||||
*/
|
||||
'clean' => [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Enable clear cache on repository changes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
'enabled' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Actions in Repository
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| create : Clear Cache on create Entry in repository
|
||||
| update : Clear Cache on update Entry in repository
|
||||
| delete : Clear Cache on delete Entry in repository
|
||||
|
|
||||
*/
|
||||
'on' => [
|
||||
'create' => true,
|
||||
'update' => true,
|
||||
'delete' => true,
|
||||
],
|
||||
],
|
||||
|
||||
'params' => [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Skip Cache Params
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
|
|
||||
| Ex: http://prettus.local/?search=lorem&skipCache=true
|
||||
|
|
||||
*/
|
||||
'skipCache' => 'skipCache',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Methods Allowed
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| methods cacheable : all, paginate, find, findByField, findWhere, getByCriteria
|
||||
|
|
||||
| Ex:
|
||||
|
|
||||
| 'only' =>['all','paginate'],
|
||||
|
|
||||
| or
|
||||
|
|
||||
| 'except' =>['find'],
|
||||
*/
|
||||
'allowed' => [
|
||||
'only' => null,
|
||||
'except' => null,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Criteria Config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Settings of request parameters names that will be used by Criteria
|
||||
|
|
||||
*/
|
||||
'criteria' => [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Accepted Conditions
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Conditions accepted in consultations where the Criteria
|
||||
|
|
||||
| Ex:
|
||||
|
|
||||
| 'acceptedConditions'=>['=','like']
|
||||
|
|
||||
| $query->where('foo','=','bar')
|
||||
| $query->where('foo','like','bar')
|
||||
|
|
||||
*/
|
||||
'acceptedConditions' => [
|
||||
'=',
|
||||
'like',
|
||||
'in',
|
||||
],
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Request Params
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Request parameters that will be used to filter the query in the repository
|
||||
|
|
||||
| Params :
|
||||
|
|
||||
| - search : Searched value
|
||||
| Ex: http://prettus.local/?search=lorem
|
||||
|
|
||||
| - searchFields : Fields in which research should be carried out
|
||||
| Ex:
|
||||
| http://prettus.local/?search=lorem&searchFields=name;email
|
||||
| http://prettus.local/?search=lorem&searchFields=name:like;email
|
||||
| http://prettus.local/?search=lorem&searchFields=name:like
|
||||
|
|
||||
| - filter : Fields that must be returned to the response object
|
||||
| Ex:
|
||||
| http://prettus.local/?search=lorem&filter=id,name
|
||||
|
|
||||
| - orderBy : Order By
|
||||
| Ex:
|
||||
| http://prettus.local/?search=lorem&orderBy=id
|
||||
|
|
||||
| - sortedBy : Sort
|
||||
| Ex:
|
||||
| http://prettus.local/?search=lorem&orderBy=id&sortedBy=asc
|
||||
| http://prettus.local/?search=lorem&orderBy=id&sortedBy=desc
|
||||
|
|
||||
| - searchJoin: Specifies the search method (AND / OR), by default the
|
||||
| application searches each parameter with OR
|
||||
| EX:
|
||||
| http://prettus.local/?search=lorem&searchJoin=and
|
||||
| http://prettus.local/?search=lorem&searchJoin=or
|
||||
|
|
||||
*/
|
||||
'params' => [
|
||||
'search' => 'search',
|
||||
'searchFields' => 'searchFields',
|
||||
'filter' => 'filter',
|
||||
'orderBy' => 'orderBy',
|
||||
'sortedBy' => 'sortedBy',
|
||||
'with' => 'with',
|
||||
'searchJoin' => 'searchJoin',
|
||||
'withCount' => 'withCount',
|
||||
],
|
||||
],
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Generator Config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
*/
|
||||
'generator' => [
|
||||
'basePath' => app()->path(),
|
||||
'rootNamespace' => 'App\\',
|
||||
'stubsOverridePath' => app()->path(),
|
||||
'paths' => [
|
||||
'models' => 'Entities',
|
||||
'repositories' => 'Repositories',
|
||||
'interfaces' => 'Repositories',
|
||||
'transformers' => 'Transformers',
|
||||
'presenters' => 'Presenters',
|
||||
'validators' => 'Validators',
|
||||
'controllers' => 'Http/Controllers',
|
||||
'provider' => 'RepositoryServiceProvider',
|
||||
'criteria' => 'Criteria',
|
||||
],
|
||||
],
|
||||
];
|
||||
68
config/sanctum.php
Normal file
68
config/sanctum.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Stateful Domains
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Requests from the following domains / hosts will receive stateful API
|
||||
| authentication cookies. Typically, these should include your local
|
||||
| and production domains which access your API via a frontend SPA.
|
||||
|
|
||||
*/
|
||||
|
||||
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
|
||||
'%s%s',
|
||||
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
|
||||
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
|
||||
))),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Sanctum Guards
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This array contains the authentication guards that will be checked when
|
||||
| Sanctum is trying to authenticate a request. If none of these guards
|
||||
| are able to authenticate the request, Sanctum will use the bearer
|
||||
| token that's present on an incoming request for authentication.
|
||||
|
|
||||
*/
|
||||
|
||||
'guard' => ['user'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Expiration Minutes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value controls the number of minutes until an issued token will be
|
||||
| considered expired. If this value is null, personal access tokens do
|
||||
| not expire. This won't tweak the lifetime of first-party sessions.
|
||||
|
|
||||
*/
|
||||
|
||||
'expiration' => null,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Sanctum Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When authenticating your first-party SPA with Sanctum you may need to
|
||||
| customize some of the middleware Sanctum uses while processing the
|
||||
| request. You may change the middleware listed below as required.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => [
|
||||
'verify_csrf_token' => VerifyCsrfToken::class,
|
||||
'encrypt_cookies' => EncryptCookies::class,
|
||||
],
|
||||
|
||||
];
|
||||
39
config/services.php
Normal file
39
config/services.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Third Party Services
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is for storing the credentials for third party services such
|
||||
| as Mailgun, Postmark, AWS and more. This file provides the de facto
|
||||
| location for this type of information, allowing packages to have
|
||||
| a conventional file to locate the various service credentials.
|
||||
|
|
||||
*/
|
||||
|
||||
'mailgun' => [
|
||||
'domain' => env('MAILGUN_DOMAIN'),
|
||||
'secret' => env('MAILGUN_SECRET'),
|
||||
'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
|
||||
],
|
||||
|
||||
'postmark' => [
|
||||
'token' => env('POSTMARK_TOKEN'),
|
||||
],
|
||||
|
||||
'ses' => [
|
||||
'key' => env('AWS_ACCESS_KEY_ID'),
|
||||
'secret' => env('AWS_SECRET_ACCESS_KEY'),
|
||||
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
|
||||
],
|
||||
|
||||
'google' => [
|
||||
'client_id' => env('GOOGLE_CLIENT_ID'),
|
||||
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
|
||||
'redirect' => env('GOOGLE_REDIRECT_URI'),
|
||||
],
|
||||
|
||||
];
|
||||
201
config/session.php
Normal file
201
config/session.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Default Session Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option controls the default session "driver" that will be used on
|
||||
| requests. By default, we will use the lightweight native driver but
|
||||
| you may specify any of the other wonderful drivers provided here.
|
||||
|
|
||||
| Supported: "file", "cookie", "database", "apc",
|
||||
| "memcached", "redis", "dynamodb", "array"
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('SESSION_DRIVER', 'file'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Lifetime
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify the number of minutes that you wish the session
|
||||
| to be allowed to remain idle before it expires. If you want them
|
||||
| to immediately expire on the browser closing, set that option.
|
||||
|
|
||||
*/
|
||||
|
||||
'lifetime' => env('SESSION_LIFETIME', 120),
|
||||
|
||||
'expire_on_close' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Encryption
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to easily specify that all of your session data
|
||||
| should be encrypted before it is stored. All encryption will be run
|
||||
| automatically by Laravel and you can use the Session like normal.
|
||||
|
|
||||
*/
|
||||
|
||||
'encrypt' => false,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session File Location
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the native session driver, we need a location where session
|
||||
| files may be stored. A default has been set for you but a different
|
||||
| location may be specified. This is only needed for file sessions.
|
||||
|
|
||||
*/
|
||||
|
||||
'files' => storage_path('framework/sessions'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Connection
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" or "redis" session drivers, you may specify a
|
||||
| connection that should be used to manage these sessions. This should
|
||||
| correspond to a connection in your database configuration options.
|
||||
|
|
||||
*/
|
||||
|
||||
'connection' => env('SESSION_CONNECTION', null),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Database Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When using the "database" session driver, you may specify the table we
|
||||
| should use to manage the sessions. Of course, a sensible default is
|
||||
| provided for you; however, you are free to change this as needed.
|
||||
|
|
||||
*/
|
||||
|
||||
'table' => 'sessions',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cache Store
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While using one of the framework's cache driven session backends you may
|
||||
| list a cache store that should be used for these sessions. This value
|
||||
| must match with one of the application's configured cache "stores".
|
||||
|
|
||||
| Affects: "apc", "dynamodb", "memcached", "redis"
|
||||
|
|
||||
*/
|
||||
|
||||
'store' => env('SESSION_STORE', null),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Sweeping Lottery
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Some session drivers must manually sweep their storage location to get
|
||||
| rid of old sessions from storage. Here are the chances that it will
|
||||
| happen on a given request. By default, the odds are 2 out of 100.
|
||||
|
|
||||
*/
|
||||
|
||||
'lottery' => [2, 100],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Name
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may change the name of the cookie used to identify a session
|
||||
| instance by ID. The name specified here will get used every time a
|
||||
| new session cookie is created by the framework for every driver.
|
||||
|
|
||||
*/
|
||||
|
||||
'cookie' => env(
|
||||
'SESSION_COOKIE',
|
||||
Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
|
||||
),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The session cookie path determines the path for which the cookie will
|
||||
| be regarded as available. Typically, this will be the root path of
|
||||
| your application but you are free to change this when necessary.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => '/',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Cookie Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may change the domain of the cookie used to identify a session
|
||||
| in your application. This will determine which domains the cookie is
|
||||
| available to in your application. A sensible default has been set.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('SESSION_DOMAIN', null),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTPS Only Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| By setting this option to true, session cookies will only be sent back
|
||||
| to the server if the browser has a HTTPS connection. This will keep
|
||||
| the cookie from being sent to you if it can not be done securely.
|
||||
|
|
||||
*/
|
||||
|
||||
'secure' => env('SESSION_SECURE_COOKIE'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| HTTP Access Only
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Setting this value to true will prevent JavaScript from accessing the
|
||||
| value of the cookie and the cookie will only be accessible through
|
||||
| the HTTP protocol. You are free to modify this option if needed.
|
||||
|
|
||||
*/
|
||||
|
||||
'http_only' => true,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Same-Site Cookies
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines how your cookies behave when cross-site requests
|
||||
| take place, and can be used to mitigate CSRF attacks. By default, we
|
||||
| will set this value to "lax" since this is a secure default value.
|
||||
|
|
||||
| Supported: "lax", "strict", "none", null
|
||||
|
|
||||
*/
|
||||
|
||||
'same_site' => 'lax',
|
||||
|
||||
];
|
||||
50
config/tinker.php
Normal file
50
config/tinker.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Console Commands
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option allows you to add additional Artisan commands that should
|
||||
| be available within the Tinker environment. Once the command is in
|
||||
| this array you may execute the command in Tinker using its name.
|
||||
|
|
||||
*/
|
||||
|
||||
'commands' => [
|
||||
// App\Console\Commands\ExampleCommand::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Auto Aliased Classes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Tinker will not automatically alias classes in your vendor namespaces
|
||||
| but you may explicitly allow a subset of classes to get aliased by
|
||||
| adding the names of each of those classes to the following list.
|
||||
|
|
||||
*/
|
||||
|
||||
'alias' => [
|
||||
//
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Classes That Should Not Be Aliased
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Typically, Tinker automatically aliases classes as you require them in
|
||||
| Tinker. However, you may wish to never alias certain classes, which
|
||||
| you may accomplish by listing the classes in the following array.
|
||||
|
|
||||
*/
|
||||
|
||||
'dont_alias' => [
|
||||
'App\Nova',
|
||||
],
|
||||
|
||||
];
|
||||
36
config/view.php
Normal file
36
config/view.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| View Storage Paths
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Most templating systems load templates from disk. Here you may specify
|
||||
| an array of paths that should be checked for your views. Of course
|
||||
| the usual Laravel view path has already been registered for you.
|
||||
|
|
||||
*/
|
||||
|
||||
'paths' => [
|
||||
resource_path('views'),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Compiled View Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines where all the compiled Blade templates will be
|
||||
| stored for your application. Typically, this is within the storage
|
||||
| directory. However, as usual, you are free to change this value.
|
||||
|
|
||||
*/
|
||||
|
||||
'compiled' => env(
|
||||
'VIEW_COMPILED_PATH',
|
||||
realpath(storage_path('framework/views'))
|
||||
),
|
||||
|
||||
];
|
||||
2
database/.gitignore
vendored
Normal file
2
database/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.sqlite
|
||||
*.sqlite-journal
|
||||
47
database/factories/UserFactory.php
Normal file
47
database/factories/UserFactory.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = User::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'name' => $this->faker->name,
|
||||
'email' => $this->faker->unique()->safeEmail,
|
||||
'email_verified_at' => now(),
|
||||
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
|
||||
'remember_token' => Str::random(10),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*
|
||||
* @return Factory
|
||||
*/
|
||||
public function unverified()
|
||||
{
|
||||
return $this->state(function (array $attributes) {
|
||||
return [
|
||||
'email_verified_at' => null,
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('uuid')->unique();
|
||||
$table->text('connection');
|
||||
$table->text('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('tokenable');
|
||||
$table->string('name');
|
||||
$table->string('token', 64)->unique();
|
||||
$table->text('abilities')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('personal_access_tokens');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('job_batches', function (Blueprint $table) {
|
||||
$table->string('id')->primary();
|
||||
$table->string('name');
|
||||
$table->integer('total_jobs');
|
||||
$table->integer('pending_jobs');
|
||||
$table->integer('failed_jobs');
|
||||
$table->text('failed_job_ids');
|
||||
$table->mediumText('options')->nullable();
|
||||
$table->integer('cancelled_at')->nullable();
|
||||
$table->integer('created_at');
|
||||
$table->integer('finished_at')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('job_batches');
|
||||
}
|
||||
};
|
||||
36
database/migrations/2024_09_09_094042_create_jobs_table.php
Normal file
36
database/migrations/2024_09_09_094042_create_jobs_table.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('jobs', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->string('queue')->index();
|
||||
$table->longText('payload');
|
||||
$table->unsignedTinyInteger('attempts');
|
||||
$table->unsignedInteger('reserved_at')->nullable();
|
||||
$table->unsignedInteger('available_at');
|
||||
$table->unsignedInteger('created_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
}
|
||||
};
|
||||
19
database/seeders/DatabaseSeeder.php
Normal file
19
database/seeders/DatabaseSeeder.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Webkul\Installer\Database\Seeders\DatabaseSeeder as KrayinDatabaseSeeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->call(KrayinDatabaseSeeder::class);
|
||||
}
|
||||
}
|
||||
1
example.txt
Normal file
1
example.txt
Normal file
@@ -0,0 +1 @@
|
||||
Hello, this is a generated file!
|
||||
20
lang/en/auth.php
Normal file
20
lang/en/auth.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Authentication Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used during authentication for various
|
||||
| messages that we need to display to the user. You are free to modify
|
||||
| these language lines according to your application's requirements.
|
||||
|
|
||||
*/
|
||||
|
||||
'failed' => 'These credentials do not match our records.',
|
||||
'password' => 'The provided password is incorrect.',
|
||||
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
|
||||
|
||||
];
|
||||
19
lang/en/pagination.php
Normal file
19
lang/en/pagination.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pagination Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used by the paginator library to build
|
||||
| the simple pagination links. You are free to change them to anything
|
||||
| you want to customize your views to better match your application.
|
||||
|
|
||||
*/
|
||||
|
||||
'previous' => '« Previous',
|
||||
'next' => 'Next »',
|
||||
|
||||
];
|
||||
22
lang/en/passwords.php
Normal file
22
lang/en/passwords.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Password Reset Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are the default lines which match reasons
|
||||
| that are given by the password broker for a password update attempt
|
||||
| has failed, such as for an invalid token or invalid new password.
|
||||
|
|
||||
*/
|
||||
|
||||
'reset' => 'Your password has been reset!',
|
||||
'sent' => 'We have emailed your password reset link!',
|
||||
'throttled' => 'Please wait before retrying.',
|
||||
'token' => 'This password reset token is invalid.',
|
||||
'user' => "We can't find a user with that email address.",
|
||||
|
||||
];
|
||||
152
lang/en/validation.php
Normal file
152
lang/en/validation.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines contain the default error messages used by
|
||||
| the validator class. Some of these rules have multiple versions such
|
||||
| as the size rules. Feel free to tweak each of these messages here.
|
||||
|
|
||||
*/
|
||||
|
||||
'accepted' => 'The :attribute must be accepted.',
|
||||
'active_url' => 'The :attribute is not a valid URL.',
|
||||
'after' => 'The :attribute must be a date after :date.',
|
||||
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
|
||||
'alpha' => 'The :attribute may only contain letters.',
|
||||
'alpha_dash' => 'The :attribute may only contain letters, numbers, dashes and underscores.',
|
||||
'alpha_num' => 'The :attribute may only contain letters and numbers.',
|
||||
'array' => 'The :attribute must be an array.',
|
||||
'before' => 'The :attribute must be a date before :date.',
|
||||
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
|
||||
'between' => [
|
||||
'numeric' => 'The :attribute must be between :min and :max.',
|
||||
'file' => 'The :attribute must be between :min and :max kilobytes.',
|
||||
'string' => 'The :attribute must be between :min and :max characters.',
|
||||
'array' => 'The :attribute must have between :min and :max items.',
|
||||
],
|
||||
'boolean' => 'The :attribute field must be true or false.',
|
||||
'confirmed' => 'The :attribute confirmation does not match.',
|
||||
'date' => 'The :attribute is not a valid date.',
|
||||
'date_equals' => 'The :attribute must be a date equal to :date.',
|
||||
'date_format' => 'The :attribute does not match the format :format.',
|
||||
'different' => 'The :attribute and :other must be different.',
|
||||
'digits' => 'The :attribute must be :digits digits.',
|
||||
'digits_between' => 'The :attribute must be between :min and :max digits.',
|
||||
'dimensions' => 'The :attribute has invalid image dimensions.',
|
||||
'distinct' => 'The :attribute field has a duplicate value.',
|
||||
'email' => 'The :attribute must be a valid email address.',
|
||||
'ends_with' => 'The :attribute must end with one of the following: :values.',
|
||||
'exists' => 'The selected :attribute is invalid.',
|
||||
'file' => 'The :attribute must be a file.',
|
||||
'filled' => 'The :attribute field must have a value.',
|
||||
'gt' => [
|
||||
'numeric' => 'The :attribute must be greater than :value.',
|
||||
'file' => 'The :attribute must be greater than :value kilobytes.',
|
||||
'string' => 'The :attribute must be greater than :value characters.',
|
||||
'array' => 'The :attribute must have more than :value items.',
|
||||
],
|
||||
'gte' => [
|
||||
'numeric' => 'The :attribute must be greater than or equal :value.',
|
||||
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
|
||||
'string' => 'The :attribute must be greater than or equal :value characters.',
|
||||
'array' => 'The :attribute must have :value items or more.',
|
||||
],
|
||||
'image' => 'The :attribute must be an image.',
|
||||
'in' => 'The selected :attribute is invalid.',
|
||||
'in_array' => 'The :attribute field does not exist in :other.',
|
||||
'integer' => 'The :attribute must be an integer.',
|
||||
'ip' => 'The :attribute must be a valid IP address.',
|
||||
'ipv4' => 'The :attribute must be a valid IPv4 address.',
|
||||
'ipv6' => 'The :attribute must be a valid IPv6 address.',
|
||||
'json' => 'The :attribute must be a valid JSON string.',
|
||||
'lt' => [
|
||||
'numeric' => 'The :attribute must be less than :value.',
|
||||
'file' => 'The :attribute must be less than :value kilobytes.',
|
||||
'string' => 'The :attribute must be less than :value characters.',
|
||||
'array' => 'The :attribute must have less than :value items.',
|
||||
],
|
||||
'lte' => [
|
||||
'numeric' => 'The :attribute must be less than or equal :value.',
|
||||
'file' => 'The :attribute must be less than or equal :value kilobytes.',
|
||||
'string' => 'The :attribute must be less than or equal :value characters.',
|
||||
'array' => 'The :attribute must not have more than :value items.',
|
||||
],
|
||||
'max' => [
|
||||
'numeric' => 'The :attribute may not be greater than :max.',
|
||||
'file' => 'The :attribute may not be greater than :max kilobytes.',
|
||||
'string' => 'The :attribute may not be greater than :max characters.',
|
||||
'array' => 'The :attribute may not have more than :max items.',
|
||||
],
|
||||
'mimes' => 'The :attribute must be a file of type: :values.',
|
||||
'mimetypes' => 'The :attribute must be a file of type: :values.',
|
||||
'min' => [
|
||||
'numeric' => 'The :attribute must be at least :min.',
|
||||
'file' => 'The :attribute must be at least :min kilobytes.',
|
||||
'string' => 'The :attribute must be at least :min characters.',
|
||||
'array' => 'The :attribute must have at least :min items.',
|
||||
],
|
||||
'multiple_of' => 'The :attribute must be a multiple of :value.',
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute format is invalid.',
|
||||
'numeric' => 'The :attribute must be a number.',
|
||||
'password' => 'The password is incorrect.',
|
||||
'present' => 'The :attribute field must be present.',
|
||||
'regex' => 'The :attribute format is invalid.',
|
||||
'required' => 'The :attribute field is required.',
|
||||
'required_if' => 'The :attribute field is required when :other is :value.',
|
||||
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||
'required_with' => 'The :attribute field is required when :values is present.',
|
||||
'required_with_all' => 'The :attribute field is required when :values are present.',
|
||||
'required_without' => 'The :attribute field is required when :values is not present.',
|
||||
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
||||
'same' => 'The :attribute and :other must match.',
|
||||
'size' => [
|
||||
'numeric' => 'The :attribute must be :size.',
|
||||
'file' => 'The :attribute must be :size kilobytes.',
|
||||
'string' => 'The :attribute must be :size characters.',
|
||||
'array' => 'The :attribute must contain :size items.',
|
||||
],
|
||||
'starts_with' => 'The :attribute must start with one of the following: :values.',
|
||||
'string' => 'The :attribute must be a string.',
|
||||
'timezone' => 'The :attribute must be a valid zone.',
|
||||
'unique' => 'The :attribute has already been taken.',
|
||||
'uploaded' => 'The :attribute failed to upload.',
|
||||
'url' => 'The :attribute format is invalid.',
|
||||
'uuid' => 'The :attribute must be a valid UUID.',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here you may specify custom validation messages for attributes using the
|
||||
| convention "attribute.rule" to name the lines. This makes it quick to
|
||||
| specify a specific custom language line for a given attribute rule.
|
||||
|
|
||||
*/
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Attributes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following language lines are used to swap our attribute placeholder
|
||||
| with something more reader friendly such as "E-Mail Address" instead
|
||||
| of "email". This simply helps us make our message more expressive.
|
||||
|
|
||||
*/
|
||||
|
||||
'attributes' => [],
|
||||
|
||||
];
|
||||
13
package.json
Normal file
13
package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.6.4",
|
||||
"laravel-vite-plugin": "^1.0.0",
|
||||
"vite": "^6.4.3"
|
||||
}
|
||||
}
|
||||
28
packages/Webkul/Activity/composer.json
Executable file
28
packages/Webkul/Activity/composer.json
Executable file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "krayin/laravel-activity",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jitendra Singh",
|
||||
"email": "jitendra@webkul.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"krayin/laravel-core": "^1.0",
|
||||
"krayin/laravel-user": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webkul\\Activity\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Webkul\\Activity\\Providers\\ActivityServiceProvider"
|
||||
],
|
||||
"aliases": {}
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
5
packages/Webkul/Activity/src/Contracts/Activity.php
Normal file
5
packages/Webkul/Activity/src/Contracts/Activity.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Contracts;
|
||||
|
||||
interface Activity {}
|
||||
5
packages/Webkul/Activity/src/Contracts/File.php
Normal file
5
packages/Webkul/Activity/src/Contracts/File.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Contracts;
|
||||
|
||||
interface File {}
|
||||
5
packages/Webkul/Activity/src/Contracts/Participant.php
Normal file
5
packages/Webkul/Activity/src/Contracts/Participant.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Contracts;
|
||||
|
||||
interface Participant {}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('activities', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('title')->nullable();
|
||||
$table->string('type');
|
||||
$table->text('comment')->nullable();
|
||||
$table->json('additional')->nullable();
|
||||
$table->datetime('schedule_from')->nullable();
|
||||
$table->datetime('schedule_to')->nullable();
|
||||
$table->boolean('is_done')->default(0);
|
||||
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('activities');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('activity_files', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->string('path');
|
||||
|
||||
$table->integer('activity_id')->unsigned();
|
||||
$table->foreign('activity_id')->references('id')->on('activities')->onDelete('cascade');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('activity_files');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('activity_participants', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
|
||||
$table->integer('activity_id')->unsigned();
|
||||
$table->foreign('activity_id')->references('id')->on('activities')->onDelete('cascade');
|
||||
|
||||
$table->integer('user_id')->nullable()->unsigned();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
|
||||
$table->integer('person_id')->nullable()->unsigned();
|
||||
$table->foreign('person_id')->references('id')->on('persons')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('activity_participants');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$table->string('location')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$table->dropColumn('location');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$table->dropForeign(['user_id']);
|
||||
|
||||
$table->unsignedInteger('user_id')->nullable()->change();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
// Disable foreign key checks temporarily.
|
||||
DB::statement('SET FOREIGN_KEY_CHECKS=0');
|
||||
|
||||
// Drop the foreign key constraint using raw SQL.
|
||||
DB::statement('ALTER TABLE '.$tablePrefix.'activities DROP FOREIGN KEY activities_user_id_foreign');
|
||||
|
||||
// Drop the index.
|
||||
DB::statement('ALTER TABLE '.$tablePrefix.'activities DROP INDEX activities_user_id_foreign');
|
||||
|
||||
// Change the column to be non-nullable.
|
||||
$table->unsignedInteger('user_id')->nullable(false)->change();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
|
||||
// Re-enable foreign key checks.
|
||||
DB::statement('SET FOREIGN_KEY_CHECKS=1');
|
||||
});
|
||||
}
|
||||
};
|
||||
111
packages/Webkul/Activity/src/Models/Activity.php
Normal file
111
packages/Webkul/Activity/src/Models/Activity.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Activity\Contracts\Activity as ActivityContract;
|
||||
use Webkul\Contact\Models\PersonProxy;
|
||||
use Webkul\Lead\Models\LeadProxy;
|
||||
use Webkul\Product\Models\ProductProxy;
|
||||
use Webkul\User\Models\UserProxy;
|
||||
use Webkul\Warehouse\Models\WarehouseProxy;
|
||||
|
||||
class Activity extends Model implements ActivityContract
|
||||
{
|
||||
/**
|
||||
* Define table name of property
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'activities';
|
||||
|
||||
/**
|
||||
* Define relationships that should be touched on save
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['user'];
|
||||
|
||||
/**
|
||||
* Cast attributes to date time
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'schedule_from' => 'datetime',
|
||||
'schedule_to' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'type',
|
||||
'location',
|
||||
'comment',
|
||||
'additional',
|
||||
'schedule_from',
|
||||
'schedule_to',
|
||||
'is_done',
|
||||
'user_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the user that owns the activity.
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(UserProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* The participants that belong to the activity.
|
||||
*/
|
||||
public function participants()
|
||||
{
|
||||
return $this->hasMany(ParticipantProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file associated with the activity.
|
||||
*/
|
||||
public function files()
|
||||
{
|
||||
return $this->hasMany(FileProxy::modelClass(), 'activity_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* The leads that belong to the activity.
|
||||
*/
|
||||
public function leads()
|
||||
{
|
||||
return $this->belongsToMany(LeadProxy::modelClass(), 'lead_activities');
|
||||
}
|
||||
|
||||
/**
|
||||
* The Person that belong to the activity.
|
||||
*/
|
||||
public function persons()
|
||||
{
|
||||
return $this->belongsToMany(PersonProxy::modelClass(), 'person_activities');
|
||||
}
|
||||
|
||||
/**
|
||||
* The leads that belong to the activity.
|
||||
*/
|
||||
public function products()
|
||||
{
|
||||
return $this->belongsToMany(ProductProxy::modelClass(), 'product_activities');
|
||||
}
|
||||
|
||||
/**
|
||||
* The Warehouse that belong to the activity.
|
||||
*/
|
||||
public function warehouses()
|
||||
{
|
||||
return $this->belongsToMany(WarehouseProxy::modelClass(), 'warehouse_activities');
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Activity/src/Models/ActivityProxy.php
Normal file
7
packages/Webkul/Activity/src/Models/ActivityProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ActivityProxy extends ModelProxy {}
|
||||
71
packages/Webkul/Activity/src/Models/File.php
Normal file
71
packages/Webkul/Activity/src/Models/File.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Webkul\Activity\Contracts\File as FileContract;
|
||||
|
||||
class File extends Model implements FileContract
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'activity_files';
|
||||
|
||||
/**
|
||||
* The attributes that should be appended to the model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['url'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'path',
|
||||
'activity_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get image url for the product image.
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return Storage::url($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image url for the product image.
|
||||
*/
|
||||
public function getUrlAttribute()
|
||||
{
|
||||
return $this->url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the activity that owns the file.
|
||||
*/
|
||||
public function activity()
|
||||
{
|
||||
return $this->belongsTo(ActivityProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$array = parent::toArray();
|
||||
|
||||
$array['url'] = $this->url;
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Activity/src/Models/FileProxy.php
Normal file
7
packages/Webkul/Activity/src/Models/FileProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class FileProxy extends ModelProxy {}
|
||||
52
packages/Webkul/Activity/src/Models/Participant.php
Normal file
52
packages/Webkul/Activity/src/Models/Participant.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Activity\Contracts\Participant as ParticipantContract;
|
||||
use Webkul\Contact\Models\PersonProxy;
|
||||
use Webkul\User\Models\UserProxy;
|
||||
|
||||
class Participant extends Model implements ParticipantContract
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $table = 'activity_participants';
|
||||
|
||||
protected $with = ['user', 'person'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'activity_id',
|
||||
'user_id',
|
||||
'person_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the activity that owns the participant.
|
||||
*/
|
||||
public function activity()
|
||||
{
|
||||
return $this->belongsTo(ActivityProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the participant.
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(UserProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the person that owns the participant.
|
||||
*/
|
||||
public function person()
|
||||
{
|
||||
return $this->belongsTo(PersonProxy::modelClass());
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Activity/src/Models/ParticipantProxy.php
Normal file
7
packages/Webkul/Activity/src/Models/ParticipantProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ParticipantProxy extends ModelProxy {}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Providers;
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Webkul\Activity\Contracts\Activity as ActivityContract;
|
||||
use Webkul\Activity\Contracts\File as FileContract;
|
||||
use Webkul\Activity\Contracts\Participant as ParticipantContract;
|
||||
use Webkul\Activity\Models\Activity;
|
||||
use Webkul\Activity\Models\File;
|
||||
use Webkul\Activity\Models\Participant;
|
||||
|
||||
class ActivityServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* Adds Laravel container bindings as a fallback so repositories that
|
||||
* type-hint the contract interfaces resolve even if Concord's
|
||||
* ModuleServiceProvider::boot() has not yet run.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bindIf(ActivityContract::class, Activity::class);
|
||||
$this->app->bindIf(FileContract::class, File::class);
|
||||
$this->app->bindIf(ParticipantContract::class, Participant::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(Router $router)
|
||||
{
|
||||
$this->loadMigrationsFrom(__DIR__.'/../Database/Migrations');
|
||||
|
||||
// Guarantee that Concord's model-proxy registry contains the Activity
|
||||
// bindings after all providers have booted. ModelProxy::modelClass()
|
||||
// looks up $concord->model($contract) — a separate store from the
|
||||
// Laravel container — so this registration is strictly necessary for
|
||||
// proxies like ActivityProxy used in Eloquent relationships.
|
||||
$this->app->booted(function () {
|
||||
$concord = app('concord');
|
||||
|
||||
if (! $concord->model(ActivityContract::class)) {
|
||||
$concord->registerModel(ActivityContract::class, Activity::class);
|
||||
}
|
||||
|
||||
if (! $concord->model(FileContract::class)) {
|
||||
$concord->registerModel(FileContract::class, File::class);
|
||||
}
|
||||
|
||||
if (! $concord->model(ParticipantContract::class)) {
|
||||
$concord->registerModel(ParticipantContract::class, Participant::class);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Providers;
|
||||
|
||||
use Webkul\Activity\Models\Activity;
|
||||
use Webkul\Activity\Models\File;
|
||||
use Webkul\Activity\Models\Participant;
|
||||
use Webkul\Core\Providers\BaseModuleServiceProvider;
|
||||
|
||||
class ModuleServiceProvider extends BaseModuleServiceProvider
|
||||
{
|
||||
protected $models = [
|
||||
Activity::class,
|
||||
File::class,
|
||||
Participant::class,
|
||||
];
|
||||
}
|
||||
175
packages/Webkul/Activity/src/Repositories/ActivityRepository.php
Executable file
175
packages/Webkul/Activity/src/Repositories/ActivityRepository.php
Executable file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Repositories;
|
||||
|
||||
use Webkul\Activity\Contracts\Activity;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class ActivityRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Activity\Contracts\Activity';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pipeline.
|
||||
*
|
||||
* @return Activity
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
$activity = parent::create($data);
|
||||
|
||||
if (isset($data['file'])) {
|
||||
app(FileRepository::class)->create([
|
||||
'name' => $data['name'] ?? $data['file']->getClientOriginalName(),
|
||||
'path' => $data['file']->store('activities/'.$activity->id),
|
||||
'activity_id' => $activity->id,
|
||||
]);
|
||||
}
|
||||
|
||||
if (! isset($data['participants'])) {
|
||||
return $activity;
|
||||
}
|
||||
|
||||
foreach ($data['participants']['users'] ?? [] as $userId) {
|
||||
$activity->participants()->create([
|
||||
'user_id' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($data['participants']['persons'] ?? [] as $personId) {
|
||||
$activity->participants()->create([
|
||||
'person_id' => $personId,
|
||||
]);
|
||||
}
|
||||
|
||||
return $activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update pipeline.
|
||||
*
|
||||
* @param int $id
|
||||
* @param string $attribute
|
||||
* @return Activity
|
||||
*/
|
||||
public function update(array $data, $id, $attribute = 'id')
|
||||
{
|
||||
$activity = parent::update($data, $id);
|
||||
|
||||
if (isset($data['participants'])) {
|
||||
$activity->participants()->delete();
|
||||
|
||||
foreach ($data['participants']['users'] ?? [] as $userId) {
|
||||
/**
|
||||
* In some cases, the component exists in an HTML form, and traditional HTML does not send an empty array.
|
||||
* Therefore, we need to check for an empty string.
|
||||
* This scenario occurs only when all participants are removed.
|
||||
*/
|
||||
if (empty($userId)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$activity->participants()->create([
|
||||
'user_id' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($data['participants']['persons'] ?? [] as $personId) {
|
||||
/**
|
||||
* In some cases, the component exists in an HTML form, and traditional HTML does not send an empty array.
|
||||
* Therefore, we need to check for an empty string.
|
||||
* This scenario occurs only when all participants are removed.
|
||||
*/
|
||||
if (empty($personId)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$activity->participants()->create([
|
||||
'person_id' => $personId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dateRange
|
||||
* @return mixed
|
||||
*/
|
||||
public function getActivities($dateRange)
|
||||
{
|
||||
$tablePrefix = \DB::getTablePrefix();
|
||||
|
||||
return $this->select(
|
||||
'activities.id',
|
||||
'activities.created_at',
|
||||
'activities.title',
|
||||
'activities.schedule_from as start',
|
||||
'activities.schedule_to as end',
|
||||
'users.name as user_name',
|
||||
)
|
||||
->addSelect(\DB::raw('IF('.$tablePrefix.'activities.is_done, "done", "") as class'))
|
||||
->leftJoin('activity_participants', 'activities.id', '=', 'activity_participants.activity_id')
|
||||
->leftJoin('users', 'activities.user_id', '=', 'users.id')
|
||||
->whereIn('type', ['call', 'meeting', 'lunch'])
|
||||
->whereBetween('activities.schedule_from', $dateRange)
|
||||
->where(function ($query) {
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$query->whereIn('activities.user_id', $userIds)
|
||||
->orWhereIn('activity_participants.user_id', $userIds);
|
||||
}
|
||||
})
|
||||
->distinct()
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $startFrom
|
||||
* @param string $endFrom
|
||||
* @param array $participants
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function isDurationOverlapping($startFrom, $endFrom, $participants, $id)
|
||||
{
|
||||
$queryBuilder = $this->leftJoin('activity_participants', 'activities.id', '=', 'activity_participants.activity_id')
|
||||
->where(function ($query) use ($startFrom, $endFrom) {
|
||||
$query->where([
|
||||
['activities.schedule_from', '<=', $startFrom],
|
||||
['activities.schedule_to', '>=', $startFrom],
|
||||
])->orWhere([
|
||||
['activities.schedule_from', '>=', $startFrom],
|
||||
['activities.schedule_from', '<=', $endFrom],
|
||||
]);
|
||||
})
|
||||
->where(function ($query) use ($participants) {
|
||||
if (is_null($participants)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($participants['users'])) {
|
||||
$query->orWhereIn('activity_participants.user_id', $participants['users']);
|
||||
}
|
||||
|
||||
if (isset($participants['persons'])) {
|
||||
$query->orWhereIn('activity_participants.person_id', $participants['persons']);
|
||||
}
|
||||
})
|
||||
->groupBy('activities.id');
|
||||
|
||||
if (! is_null($id)) {
|
||||
$queryBuilder->where('activities.id', '!=', $id);
|
||||
}
|
||||
|
||||
return $queryBuilder->count() ? true : false;
|
||||
}
|
||||
}
|
||||
19
packages/Webkul/Activity/src/Repositories/FileRepository.php
Executable file
19
packages/Webkul/Activity/src/Repositories/FileRepository.php
Executable file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Repositories;
|
||||
|
||||
use Webkul\Activity\Contracts\File;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class FileRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify model class name.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return File::class;
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Activity/src/Repositories/ParticipantRepository.php
Executable file
18
packages/Webkul/Activity/src/Repositories/ParticipantRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class ParticipantRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Activity\Contracts\Participant';
|
||||
}
|
||||
}
|
||||
183
packages/Webkul/Activity/src/Traits/LogsActivity.php
Normal file
183
packages/Webkul/Activity/src/Traits/LogsActivity.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Traits;
|
||||
|
||||
use Webkul\Activity\Repositories\ActivityRepository;
|
||||
use Webkul\Attribute\Contracts\AttributeValue;
|
||||
use Webkul\Attribute\Repositories\AttributeValueRepository;
|
||||
|
||||
trait LogsActivity
|
||||
{
|
||||
/**
|
||||
* The "booted" method of the model.
|
||||
*/
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::created(function ($model) {
|
||||
if (! method_exists($model->entity ?? $model, 'activities')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $model instanceof AttributeValue) {
|
||||
$activity = app(ActivityRepository::class)->create([
|
||||
'type' => 'system',
|
||||
'title' => trans('admin::app.activities.created'),
|
||||
'is_done' => 1,
|
||||
'user_id' => auth()->check()
|
||||
? auth()->id()
|
||||
: null,
|
||||
]);
|
||||
|
||||
$model->activities()->attach($activity->id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static::logActivity($model);
|
||||
});
|
||||
|
||||
static::updated(function ($model) {
|
||||
if (! method_exists($model->entity ?? $model, 'activities')) {
|
||||
return;
|
||||
}
|
||||
|
||||
static::logActivity($model);
|
||||
});
|
||||
|
||||
static::deleting(function ($model) {
|
||||
if (! method_exists($model->entity ?? $model, 'activities')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$model->activities()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create activity.
|
||||
*/
|
||||
protected static function logActivity($model)
|
||||
{
|
||||
$customAttributes = [];
|
||||
|
||||
if (method_exists($model, 'getCustomAttributes')) {
|
||||
$customAttributes = $model->getCustomAttributes()->pluck('code')->toArray();
|
||||
}
|
||||
|
||||
$updatedAttributes = static::getUpdatedAttributes($model);
|
||||
|
||||
foreach ($updatedAttributes as $attributeCode => $attributeData) {
|
||||
if (in_array($attributeCode, $customAttributes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributeCode = $model->attribute?->name ?: $attributeCode;
|
||||
|
||||
$activity = app(ActivityRepository::class)->create([
|
||||
'type' => 'system',
|
||||
'title' => trans('admin::app.activities.updated', ['attribute' => $attributeCode]),
|
||||
'is_done' => 1,
|
||||
'additional' => json_encode([
|
||||
'attribute' => $attributeCode,
|
||||
'new' => [
|
||||
'value' => $attributeData['new'],
|
||||
'label' => static::getAttributeLabel($attributeData['new'], $model->attribute),
|
||||
],
|
||||
'old' => [
|
||||
'value' => $attributeData['old'],
|
||||
'label' => static::getAttributeLabel($attributeData['old'], $model->attribute),
|
||||
],
|
||||
]),
|
||||
'user_id' => auth()->id(),
|
||||
]);
|
||||
|
||||
if ($model instanceof AttributeValue) {
|
||||
$model->entity->activities()->attach($activity->id);
|
||||
} else {
|
||||
$model->activities()->attach($activity->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attribute label.
|
||||
*/
|
||||
protected static function getAttributeLabel($value, $attribute)
|
||||
{
|
||||
return app(AttributeValueRepository::class)->getAttributeLabel($value, $attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create activity.
|
||||
*/
|
||||
protected static function getUpdatedAttributes($model)
|
||||
{
|
||||
$updatedAttributes = [];
|
||||
|
||||
foreach ($model->getDirty() as $key => $value) {
|
||||
if (in_array($key, [
|
||||
'id',
|
||||
'attribute_id',
|
||||
'entity_id',
|
||||
'entity_type',
|
||||
'updated_at',
|
||||
])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newValue = static::decodeValueIfJson($value);
|
||||
|
||||
$oldValue = static::decodeValueIfJson($model->getOriginal($key));
|
||||
|
||||
if ($newValue != $oldValue) {
|
||||
$updatedAttributes[$key] = [
|
||||
'new' => $newValue,
|
||||
'old' => $oldValue,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $updatedAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert value if json.
|
||||
*/
|
||||
protected static function decodeValueIfJson($value)
|
||||
{
|
||||
if (
|
||||
! is_array($value)
|
||||
&& json_decode($value, true)
|
||||
) {
|
||||
$value = json_decode($value, true);
|
||||
}
|
||||
|
||||
if (! is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
static::ksortRecursive($value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort array recursively.
|
||||
*/
|
||||
protected static function ksortRecursive(&$array)
|
||||
{
|
||||
if (! is_array($array)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ksort($array);
|
||||
|
||||
foreach ($array as &$value) {
|
||||
if (! is_array($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
static::ksortRecursive($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
5
packages/Webkul/Admin/.gitignore
vendored
Executable file
5
packages/Webkul/Admin/.gitignore
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
/node_modules
|
||||
/package-lock.json
|
||||
npm-debug.log
|
||||
/playwright-report
|
||||
/test-results
|
||||
35
packages/Webkul/Admin/composer.json
Executable file
35
packages/Webkul/Admin/composer.json
Executable file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "krayin/laravel-admin",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jitendra Singh",
|
||||
"email": "jitendra@webkul.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"krayin/laravel-attribute": "^1.0",
|
||||
"krayin/laravel-contact": "^1.0",
|
||||
"krayin/laravel-core": "^1.0",
|
||||
"krayin/laravel-email": "^1.0",
|
||||
"krayin/laravel-lead": "^1.0",
|
||||
"krayin/laravel-product": "^1.0",
|
||||
"krayin/laravel-tag": "^1.0",
|
||||
"krayin/laravel-ui": "^1.0",
|
||||
"krayin/laravel-user": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webkul\\Admin\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Webkul\\Admin\\Providers\\AdminServiceProvider"
|
||||
],
|
||||
"aliases": {}
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
1
packages/Webkul/Admin/example.txt
Normal file
1
packages/Webkul/Admin/example.txt
Normal file
@@ -0,0 +1 @@
|
||||
Hello, this is a generated file!
|
||||
36
packages/Webkul/Admin/package.json
Normal file
36
packages/Webkul/Admin/package.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@types/node": "^22.7.8",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"axios": "^1.7.4",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"postcss": "^8.4.23",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"vite": "^5.4.12",
|
||||
"vue": "^3.4.21"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vee-validate/i18n": "^4.9.1",
|
||||
"@vee-validate/rules": "^4.9.1",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"chartjs-chart-funnel": "^4.2.1",
|
||||
"dompurify": "^3.1.7",
|
||||
"dotenv": "^16.4.7",
|
||||
"fast-csv": "^5.0.5",
|
||||
"flatpickr": "^4.6.13",
|
||||
"mitt": "^3.0.1",
|
||||
"playwright": "^1.48.1",
|
||||
"readline-sync": "^1.4.10",
|
||||
"vee-validate": "^4.9.1",
|
||||
"vue-cal": "^4.9.0",
|
||||
"vue-flatpickr": "^2.3.0",
|
||||
"vuedraggable": "^4.1.0"
|
||||
}
|
||||
}
|
||||
3
packages/Webkul/Admin/postcss.config.cjs
Normal file
3
packages/Webkul/Admin/postcss.config.cjs
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = ({ env }) => ({
|
||||
plugins: [require("tailwindcss")(), require("autoprefixer")()],
|
||||
});
|
||||
60
packages/Webkul/Admin/src/Bouncer.php
Executable file
60
packages/Webkul/Admin/src/Bouncer.php
Executable file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin;
|
||||
|
||||
use Webkul\User\Repositories\UserRepository;
|
||||
|
||||
class Bouncer
|
||||
{
|
||||
/**
|
||||
* Checks if user allowed or not for certain action
|
||||
*
|
||||
* @param string $permission
|
||||
* @return void
|
||||
*/
|
||||
public function hasPermission($permission)
|
||||
{
|
||||
if (auth()->guard('user')->check() && auth()->guard('user')->user()->role->permission_type == 'all') {
|
||||
return true;
|
||||
} else {
|
||||
if (! auth()->guard('user')->check() || ! auth()->guard('user')->user()->hasPermission($permission)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if user allowed or not for certain action
|
||||
*
|
||||
* @param string $permission
|
||||
* @return void
|
||||
*/
|
||||
public static function allow($permission)
|
||||
{
|
||||
if (! auth()->guard('user')->check() || ! auth()->guard('user')->user()->hasPermission($permission)) {
|
||||
abort(401, 'This action is unauthorized');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return user ids of current user's groups
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getAuthorizedUserIds()
|
||||
{
|
||||
$user = auth()->guard('user')->user();
|
||||
|
||||
if ($user->view_permission == 'global') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($user->view_permission == 'group') {
|
||||
return app(UserRepository::class)->getCurrentUserGroupsUserIds();
|
||||
} else {
|
||||
return [$user->id];
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user