# Blogs Portal — Laravel 10 / PHP 8.2

A multi-user blog platform with three roles (Super Admin, Reseller, Normal User), unlimited-depth categories, lifetime blog packages, PayPal payments, and a Dark Green & Gold premium theme.

---

## Features

### Roles & Permissions

| Role | Can do |
|---|---|
| **Super Admin** | Manage categories (unlimited nesting), packages, users, resellers, invoices (create / mark paid / mark unpaid), moderate blogs |
| **Reseller** | Write & publish blogs **instantly** (no approval), edit/delete own posts, buy more blog quota via packages, pay invoices via PayPal |
| **Normal User** | Browse blogs, buy writer packages, pay invoices via PayPal — admin then promotes them to reseller |

### Key Capabilities

- **Unlimited category nesting** (parent → child → grandchild → ∞) via self-referencing `parent_id`.
- **Dynamic packages** — superadmin creates and edits packages (name, blogs count, price, features list, featured flag) via `/admin/packages`. No code changes needed.
- **Site Settings panel** at `/admin/settings` with 3 tabs:
  - **General** — site name, tagline, logo, favicon, contact email
  - **SEO** — meta title/description/keywords, OpenGraph (title/description/image), Twitter card, Google Analytics, Search Console verification
  - **Security** — Google reCAPTCHA v2 toggle (master switch + per-form: login, register, contact)
- **One-time pricing** packages — pay once, blogs live forever (no recurring fees).
- **Multi-language blogs** — write in any language (per-post `language` code).
- **PayPal integration** with full create-order + capture flow (`srmklive/paypal`).
- **Manual invoicing** — admin can create custom invoices, mark them paid/unpaid.
- **Three separate dashboards**, each with its own left-side menu.
- **Per-user profile** for all three roles (avatar, bio, social links).
- **Bootstrap 5** UI with custom Dark Green (`#1B3B2F`) + Gold (`#D4AF37`) theme.
- **Playfair Display + Lora** fonts for editorial feel.

---

## Requirements

- PHP **8.2+** with extensions: `mbstring`, `pdo_mysql`, `openssl`, `tokenizer`, `xml`, `ctype`, `json`, `bcmath`, `fileinfo`, `gd` (or `imagick`)
- **Composer 2.x**
- **MySQL 5.7+** or **MariaDB 10.3+**
- A web server (Apache, Nginx) or `php artisan serve` for local development

---

## Installation

```bash
# 1. Unzip
unzip blogs-portal.zip
cd blogs-portal

# 2. Install dependencies
composer install

# 3. Environment
cp .env.example .env
php artisan key:generate

# 4. Configure your database in .env
#    DB_DATABASE=blogs_portal
#    DB_USERNAME=root
#    DB_PASSWORD=

# 5. Create the database in MySQL
#    mysql -u root -p -e "CREATE DATABASE blogs_portal CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"

# 6. Run migrations + seeders
php artisan migrate --seed

# 7. (Optional) Storage symlink — only needed if you later use Storage::disk('public')
php artisan storage:link

# 8. Make folders writable (Linux/macOS)
chmod -R 775 storage bootstrap/cache public/uploads

# 9. Start the dev server
php artisan serve
```

Open <http://localhost:8000>

---

## Test Credentials

After seeding, three users exist (all with password `password`):

| Role | Email | Username | Notes |
|---|---|---|---|
| Super Admin | `admin@blogsportal.test` | `admin` | Full control |
| Reseller | `jane@blogsportal.test` | `jane` | 10-blog quota, 6 sample posts published |
| Normal User | `john@blogsportal.test` | `john` | Browses & buys packages |

You can sign in by email **or** username.

---

## PayPal Setup

The project uses `srmklive/paypal` (REST API).

1. Create a sandbox account at <https://developer.paypal.com>.
2. Get your sandbox **Client ID** and **Client Secret**.
3. Add them to `.env`:

```
PAYPAL_MODE=sandbox
PAYPAL_SANDBOX_CLIENT_ID=YOUR_CLIENT_ID
PAYPAL_SANDBOX_CLIENT_SECRET=YOUR_CLIENT_SECRET
PAYPAL_CURRENCY=USD
```

For production, switch `PAYPAL_MODE=live` and supply `PAYPAL_LIVE_*` credentials.

### Payment flow

1. User clicks **Pay with PayPal** on an unpaid invoice.
2. They're redirected to PayPal's hosted approval page.
3. After approval, PayPal redirects them back to `/paypal/success`.
4. The order is captured server-side, a `payments` row is logged, the invoice is marked **paid**.
5. If the invoice was for a package and the user is a reseller, their `blogs_quota` is incremented automatically.

---

## Folder Structure

```
blogs-portal/
├── app/
│   ├── Console/Kernel.php
│   ├── Exceptions/Handler.php
│   ├── Http/
│   │   ├── Controllers/
│   │   │   ├── Admin/      (7 controllers)
│   │   │   ├── Auth/       (5 controllers)
│   │   │   ├── Reseller/   (4 controllers)
│   │   │   ├── User/       (3 controllers)
│   │   │   ├── FrontendController.php
│   │   │   └── PayPalController.php
│   │   ├── Kernel.php
│   │   └── Middleware/
│   │       └── CheckRole.php   ← role gate
│   ├── Models/             (User, Category, Package, Blog, Invoice, Payment)
│   └── Providers/
├── config/                 (app, auth, database, paypal, etc.)
├── database/
│   ├── migrations/         (7 migrations)
│   └── seeders/            (User, Package, Category, Blog)
├── public/
│   ├── css/app.css         ← theme
│   ├── js/app.js
│   ├── uploads/            ← avatars + blog images
│   └── index.php
├── resources/views/
│   ├── admin/              ← admin dashboard views
│   ├── auth/               ← login, register, profile, etc.
│   ├── frontend/           ← public site
│   ├── layouts/            ← public, dashboard, auth
│   ├── partials/           ← nav, footer, sidebars per role
│   ├── reseller/           ← reseller dashboard views
│   └── user/               ← user dashboard views
├── routes/
│   ├── web.php             ← all routes
│   ├── api.php
│   └── console.php
└── README.md
```

---

## URL Map

| URL | Who | Purpose |
|---|---|---|
| `/` | Public | Home page |
| `/blogs` | Public | All blogs (with search) |
| `/blog/{slug}` | Public | Single blog |
| `/category/{slug}` | Public | Blogs in a category (and all sub-categories) |
| `/author/{username}` | Public | Author profile + posts |
| `/packages` | Public | Pricing |
| `/login`, `/register`, `/forgot-password` | Guest | Auth |
| `/admin/dashboard` | Super Admin | Admin home |
| `/admin/categories` | Super Admin | Manage categories (unlimited nesting) |
| `/admin/packages` | Super Admin | Manage packages |
| `/admin/users` | Super Admin | All users + role/status |
| `/admin/resellers/create` | Super Admin | Create reseller with quota |
| `/admin/invoices` | Super Admin | Invoice list, create, mark paid/unpaid |
| `/reseller/dashboard` | Reseller | Reseller home |
| `/reseller/blogs` | Reseller | My blogs (CRUD, auto-publish) |
| `/reseller/packages` | Reseller | Buy more quota |
| `/reseller/invoices` | Reseller | My invoices (pay via PayPal) |
| `/user/dashboard` | User | User home |
| `/user/packages` | User | Buy writer package |
| `/user/invoices` | User | My invoices (pay via PayPal) |
| `/profile` | All authed | Edit own profile / avatar / password |
| `/paypal/process/{invoice}` | Authed | Begin PayPal checkout |
| `/paypal/success` | Authed | PayPal return — captures the payment |

---

## How the Quota System Works

- Each reseller has `blogs_quota` (lifetime allowance) and `blogs_used` (incremented when they publish).
- Reseller's "remaining" = `blogs_quota - blogs_used`.
- When remaining = 0, they're redirected to packages page.
- When admin marks a package-linked invoice as **paid** (or PayPal completes), the user's `blogs_quota` is incremented by `package.blogs_count`.
- Deleting a published blog does **not** refund the quota slot.

---

## Customization

### Change colors

Edit `public/css/app.css` — top of file:

```css
:root {
    --primary: #1B3B2F;       /* main green */
    --primary-dark: #0F2419;
    --accent: #D4AF37;        /* gold */
    /* ... */
}
```

### Add your own categories

`/admin/categories` → **+ Add Category**. Pick a parent or leave blank for a root category. Nest as deep as you want.

### Add your own packages

`/admin/packages` → **+ New Package**. Set blogs count, price, and one feature per line.

---

## Production Notes

- Set `APP_ENV=production` and `APP_DEBUG=false` in `.env`.
- Run `php artisan config:cache && php artisan route:cache && php artisan view:cache`.
- Point your web server's document root to `public/` (never the project root).
- Use a real mailer (`MAIL_MAILER=smtp` with proper credentials) so password resets actually send.
- Switch PayPal to `PAYPAL_MODE=live` and provide live credentials.
- Ensure `storage/`, `bootstrap/cache/`, `public/uploads/` are writable by the web user.

---

## Troubleshooting

**"Class CheckRole not found"** — Run `composer dump-autoload`.

**"SQLSTATE[42000]: Syntax error" on migrate** — Your MySQL version is too old. Upgrade to MySQL 5.7+ / MariaDB 10.3+.

**PayPal redirect fails** — Check that `PAYPAL_SANDBOX_CLIENT_ID` and `_SECRET` are set, and that `APP_URL` is reachable from your browser (PayPal redirects back to it).

**Avatars / blog images don't appear** — Ensure `public/uploads/` exists and is writable. The app saves directly here (no storage symlink needed).

**Login redirects to wrong dashboard** — Each role has its own dashboard under `/admin`, `/reseller`, `/user`. The `/dashboard` URL routes you to the correct one based on `users.role`.

---

## License

MIT — do whatever you want with it.

Built on Laravel 10 / PHP 8.2.
