Metadata-Version: 2.4
Name: article-management-system
Version: 1.1.1
Summary: A Flask-based Articles Management System with SEO optimization, admin panel, and maintenance features
Home-page: https://github.com
Author: Rahul Naik
Author-email: Rahul Naik <rnnutube@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com
Project-URL: Documentation, https://github.com
Project-URL: Repository, https://github.com
Project-URL: Issues, https://github.com
Keywords: flask,cms,articles,seo,postgresql,content-management
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Content Management System
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Framework :: Flask
Classifier: Environment :: Web Environment
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Flask>=2.3.0
Requires-Dist: Flask-SQLAlchemy>=3.0.0
Requires-Dist: Flask-Migrate>=4.0.0
Requires-Dist: Flask-Login>=0.6.0
Requires-Dist: Flask-WTF>=1.1.0
Requires-Dist: psycopg2-binary>=2.9.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: beautifulsoup4>=4.12.0
Requires-Dist: lxml>=4.9.0
Requires-Dist: apscheduler>=3.10.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-flask>=1.2.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: flake8>=6.0.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
Dynamic: author
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python

# Article Management System

A comprehensive Flask-based Content Management System (CMS) designed for managing articles with advanced SEO optimization, admin panel, and automated maintenance features.

## Features

### Core Functionality
- **Article Management**: Create, read, update, and delete articles with server-side rendering
- **SEO Optimization**:
  - Meta tag management (title, description, keywords)
  - JSON-LD schema.org structured data
  - Self-canonicalization
  - Descriptive URLs (auto-generated slugs)
  - SEO scoring and recommendations
- **HTML Import**: Automatically parse and extract article data from HTML with schema.org markup
- **Admin Panel**: Full-featured admin interface for content management
- **Responsive Design**: Mobile-friendly horizontal card layout with Bootstrap 5
- **Pagination**: Efficiently display 9 articles per page with full pagination support
- **User Authentication**: Secure login/registration system with role-based access control
- **Comments System**: Integrated with rcomments package for threaded comments
- **Likes/Dislikes**: User engagement tracking
- **View Tracking**: Automatic view count incrementation
- **Maintenance Automation**:
  - Auto-delete articles older than configurable threshold (default: 30 days)
  - Keep maximum number of articles (default: 90)
  - Scheduled daily maintenance with APScheduler
  - Manual maintenance trigger

### API Endpoints
Full RESTful API for React/TypeScript frontend integration:
- `GET /api/articles` - Paginated article listing
- `GET /api/article/<slug>` - Single article details
- `GET /api/article/<slug>/comments` - Comments with pagination
- `POST /api/article/<slug>/comment` - Add comment (authenticated)
- `DELETE /api/comment/<id>` - Delete comment
- `POST /api/article/<slug>/like` - Toggle like/dislike
- `GET /api/admin/analytics` - Admin analytics dashboard
- `POST /api/admin/maintenance/run` - Manual maintenance trigger
- `POST /api/admin/seo/analyze` - SEO score analysis

## Installation

### Prerequisites
- Python 3.8+
- PostgreSQL 10+
- pip (Python package installer)

### Basic Installation

```bash
# Install from PyPI
pip install article-management-system

```

### Database Setup

1. Create a PostgreSQL database:
```sql
CREATE DATABASE article_management;
CREATE USER article_user WITH PASSWORD 'your-password';
GRANT ALL PRIVILEGES ON DATABASE article_management TO article_user;
```

2. Configure environment variables (or use `.env` file):
```bash
export DATABASE_URL=postgresql://article_user:your-password@localhost:5432/article_management
export SECRET_KEY=your-secret-key-here
export SITE_URL=http://yourdomain.com
```

### Initialize Database

```bash
# Initialize database and create default admin user
flask init-db

# Or using the CLI command
ams-cli init-db
```



## Configuration

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `SECRET_KEY` | (required) | Flask secret key for sessions |
| `DATABASE_URL` | (required) | PostgreSQL connection URL |
| `SITE_URL` | `http://localhost:5000` | Base URL of your site |
| `SITE_NAME` | `Article Management System` | Site name for meta tags |
| `ARTICLES_PER_PAGE` | `9` | Number of articles per page |
| `MAINTENANCE_DAYS_THRESHOLD` | `30` | Delete articles older than X days |
| `MAINTENANCE_MAX_ARTICLES` | `90` | Maximum articles to keep |
| `RCOMMENTS_ENABLED` | `true` | Enable/disable comments |

### Database Configuration

The system supports flexible database configuration:

**Option 1: Full DATABASE_URL**
```bash
export DATABASE_URL=postgresql://user:password@localhost:5432/dbname
```

**Option 2: Individual components**
```bash
export DB_USER=myuser
export DB_PASSWORD=mypassword
export DB_HOST=localhost
export DB_PORT=5432
export DB_NAME=article_management
```

**Option 3: SQLite for development** (not recommended for production)
```bash
export DATABASE_URL=sqlite:///dev.db
```

### Custom Configuration Class

You can create a custom configuration class to override any setting:

```python
from article_management.config import Config

class CustomConfig(Config):
    ARTICLES_PER_PAGE = 12
    MAINTENANCE_DAYS_THRESHOLD = 60
    SITE_NAME = "My Custom Site"
    SITE_URL = "https://mywebsite.com"
    # Override any other settings
```

Then pass it to `create_app()`:
```python
from article_management import create_app
app = create_app('my_module.CustomConfig')
```

## Customization Guide

### Custom Authentication (OAuth, SSO, etc.)

The system is designed to be extensible. You can replace or extend the authentication system:

**1. Create a custom User model** (optional):
```python
# models.py
from article_management import db
from flask_login import UserMixin

class CustomUser(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True, nullable=False)
    # Add OAuth fields: oauth_provider, oauth_id, avatar_url, etc.
```

**2. Create custom auth routes**:
```python
# routes/custom_auth.py
from flask import Blueprint, redirect, url_for
from flask_login import login_user

custom_auth_bp = Blueprint('custom_auth', __name__)

@custom_auth_bp.route('/login/google')
def google_login():
    # Implement OAuth flow
    # Redirect to Google OAuth endpoint
    pass

@custom_auth_bp.route('/login/google/callback')
def google_callback():
    # Handle OAuth callback
    # Get or create user
    # login_user(user)
    return redirect(url_for('main.index'))
```

**3. Override the auth blueprint**:
```python
# In your application factory
def create_app(config_class='article_management.config.Config'):
    app = Flask(__name__)
    app.config.from_object(config_class)
    
    # Don't register the default auth blueprint
    # from article_management.routes.auth import bp as auth_bp
    # app.register_blueprint(auth_bp, url_prefix='/auth')
    
    # Register your custom auth instead
    from myapp.routes.custom_auth import custom_auth_bp
    app.register_blueprint(custom_auth_bp, url_prefix='/auth')
```

**4. Use Flask-Dance or Authlib** (recommended for OAuth):
```python
from flask_dance.contrib.google import make_google_blueprint

google_bp = make_google_blueprint(
    client_id=os.getenv('GOOGLE_CLIENT_ID'),
    client_secret=os.getenv('GOOGLE_CLIENT_SECRET'),
    scope=["profile", "email"]
)
app.register_blueprint(google_bp, url_prefix="/login")
```

### Custom Templates

Override any template by creating a `templates/` directory and setting `TEMPLATES_PATH` in your config:

```python
class CustomConfig(Config):
    TEMPLATES_PATH = ['/path/to/custom/templates', 'article_management/templates']
```

Flask will search paths in order, allowing you to override specific templates while keeping the rest.

### Custom Static Files

Add custom CSS/JS by placing files in your own static directory:

```python
class CustomConfig(Config):
    STATIC_FOLDER = '/path/to/custom/static'
```

Or use Flask's `send_static_file` override for more control.

### Adding New Routes

Create a new blueprint in `routes/` and register it in your app factory:

```python
# routes/custom.py
from flask import Blueprint, render_template

custom_bp = Blueprint('custom', __name__)

@custom_bp.route('/custom-page')
def custom_page():
    return render_template('custom_page.html')
```

Then in your app:
```python
from myapp.routes.custom import custom_bp
app.register_blueprint(custom_bp)
```

### Extending the Article Model

Add custom fields to the Article model by creating a migration:

```python
# In a migration file
op.add_column('articles', sa.Column('custom_field', sa.String(500)))
```

Then update your forms and templates accordingly.

## Latest Updates (v1.1.0)

### Recent Improvements

1. **Enhanced Reading Experience** (March 2026)
   - Fixed article content width alignment with title (now both 800px)
   - Improved typography with serif fonts (Georgia, Times New Roman)
   - Better line-height (1.8) and font size (1.125rem)
   - Text justification with hyphenation for clean flow
   - Enhanced heading hierarchy with visual styling
   - Improved blockquotes, lists, code blocks, and tables
   - Responsive design with mobile-friendly padding

2. **Maintenance Fixes** (March 2026)
   - Fixed `MaintenanceSettings.run_maintenance()` to work regardless of `is_enabled` flag
   - Manual "Run Maintenance Now" button now always executes
   - Fixed missing `MaintenanceSettings` import in API routes
   - Removed CSRF exemption issue from API endpoint

3. **Bug Fixes**
   - Fixed import errors in API routes
   - Improved error handling in maintenance tasks

## API Reference

### Authentication Endpoints
- `GET /auth/login` - Login page
- `POST /auth/login` - Login submission
- `GET /auth/register` - Registration page
- `POST /auth/register` - Registration submission
- `GET /auth/logout` - Logout

### Article Endpoints
- `GET /api/articles` - Paginated article listing
  - Query params: `page`, `per_page`, `sort_by` (date_published, view_count), `order` (asc, desc)
- `GET /api/article/<slug>` - Single article details with JSON-LD
- `GET /api/article/<slug>/comments` - Paginated comments
- `POST /api/article/<slug>/comment` - Add comment (requires auth)
- `DELETE /api/comment/<id>` - Delete comment (requires admin or comment author)
- `POST /api/article/<slug>/like` - Toggle like/dislike (requires auth)

### Admin Endpoints
- `GET /api/admin/analytics` - Analytics dashboard data
- `POST /api/admin/maintenance/run` - Manually trigger maintenance (requires admin)
- `POST /api/admin/seo/analyze` - SEO score analysis (requires admin)

## CLI Commands

The package includes a powerful CLI:

```bash
# Initialize database and create admin
ams-cli init-db

# Create admin user
ams-cli create-admin

# List all articles
ams-cli list-articles

# Delete article by ID
ams-cli delete-article 123

# Run maintenance manually
ams-cli run-maintenance

# Export all articles to JSON
ams-cli export-articles -o backup.json
```

## Project Structure

```
article_management/
├── __init__.py          # Application factory
├── config.py            # Configuration classes
├── models.py            # Database models
├── seo_utils.py         # SEO utilities
├── html_parser.py       # HTML content parser
├── forms.py             # WTForms definitions
├── decorators.py        # Custom decorators
├── cli.py               # CLI commands
├── routes/
│   ├── __init__.py
│   ├── main.py          # Public routes
│   ├── admin.py         # Admin routes
│   ├── auth.py          # Authentication routes
│   └── api.py           # API endpoints
├── templates/           # Jinja2 templates
│   ├── base.html
│   ├── index.html
│   ├── article_detail.html
│   ├── auth/
│   └── admin/
├── static/
│   ├── css/style.css
│   └── js/main.js
└── wsgi.py              # WSGI entry point
```

## Database Schema

### Main Tables

- **users**: User accounts with authentication
- **articles**: Article content with SEO fields
- **comments**: Threaded comments (integrated with rcomments)
- **likes**: User likes/dislikes tracking
- **maintenance_settings**: Maintenance configuration

### Relationships

- User → Comments (one-to-many)
- User → Likes (one-to-many)
- Article → Comments (one-to-many, cascade delete)
- Article → Likes (one-to-many, cascade delete)
- Comment → Replies (self-referential)

## Deployment

### Production Configuration

1. **Environment Setup**:
```bash
export FLASK_ENV=production
export SECRET_KEY=your-very-secure-secret-key
export DATABASE_URL=postgresql://user:pass@host:5432/db
```

2. **Use a Production WSGI Server**:
```bash
# Using Gunicorn
pip install gunicorn
gunicorn -w 4 "article_management.wsgi:app" -b 0.0.0.0:8000
```

3. **Set up Systemd service** (Linux):
```ini
[Unit]
Description=Article Management System
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/app
Environment="PATH=/path/to/venv/bin"
EnvironmentFile=/path/to/.env
ExecStart=/path/to/venv/bin/gunicorn -w 4 "article_management.wsgi:app" -b 127.0.0.1:8000

[Install]
WantedBy=multi-user.target
```

4. **Nginx Configuration**:
```nginx
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
```

### Database Migrations

```bash
# Initialize migrations
flask db init

# Create migration
flask db migrate -m "Description"

# Apply migration
flask db upgrade
```

## Testing

Run tests with pytest:

```bash
pytest tests/
```

## Security Features

- Password hashing with werkzeug
- CSRF protection with Flask-WTF
- SQL injection prevention with SQLAlchemy
- XSS protection in templates
- Authentication required for admin routes
- Role-based access control (admin/user)
- Secure session management

## Extending the Package

### Custom Templates

Override templates by creating a `templates/` directory and setting `TEMPLATES_PATH` in config.

### Custom Static Files

Add custom CSS/JS by placing files in `static/` directory.

### Adding New Routes

Create a new blueprint in `routes/` and register it in `__init__.py`.

## Troubleshooting

### Common Issues

1. **Database connection error**:
   - Check PostgreSQL is running
   - Verify credentials in `DATABASE_URL`
   - Ensure database exists

2. **Template not found**:
   - Check Flask can find the templates directory
   - Verify package installation with `pip install -e .`

3. **Static files not loading**:
   - Ensure `static/` folder exists
   - Check file permissions

4. **Migrations fail**:
   - Ensure database user has proper privileges
   - Check Flask-Migrate is installed


## License

MIT License - see LICENSE file for details



## Changelog

### v1.1.0 (March 2026)
- **Reading Experience**: Completely redesigned article layout with consistent 800px width, serif typography, and professional publishing-quality styling
- **Maintenance Fixes**: Manual maintenance now works correctly regardless of auto-maintenance setting
- **Bug Fixes**: Fixed missing MaintenanceSettings import in API routes
- **Code Quality**: Removed problematic CSRF import, improved error handling

### v1.0.0
- Initial release
- Full CRUD operations for articles
- SEO optimization with schema.org
- HTML import with automatic parsing
- Admin dashboard
- User authentication
- Comments system (rcomments integration)
- Likes/dislikes
- Maintenance automation
- REST API for frontend integration
- Responsive Bootstrap 5 UI

## Usage

### Running the Application

```bash
# Set Flask app
export FLASK_APP=article_management.wsgi:app
export FLASK_ENV=development

# Run development server
flask run
```

Or using the WSGI file directly:
```bash
python -m article_management.wsgi
```

### Admin Panel

Access the admin panel at `/admin` after logging in with admin credentials.

**Features:**
- Dashboard with statistics
- Create articles by uploading HTML or pasting content
- Edit existing articles
- Manage all articles with search/filter
- Configure maintenance settings
- Run maintenance manually
- SEO analysis tool

### Creating Articles

#### Method 1: HTML Upload
Upload an HTML file with schema.org Article markup:

```html
<article itemscope itemtype="https://schema.org/Article">
    <header>
        <h1 itemprop="headline">Article Title</h1>
        <meta itemprop="datePublished" content="2026-03-24">
        <meta itemprop="dateModified" content="2026-03-24">
    </header>

    <div itemprop="articleBody">
        <h2>Section Title</h2>
        <p>Article content...</p>
    </div>
</article>
```

#### Method 2: Manual Entry
Fill in all fields manually through the admin form.

**Required HTML Structure:**
- `<article itemscope itemtype="https://schema.org/Article">`
- `<h1 itemprop="headline">` - Article title
- `<meta itemprop="datePublished">` - Publication date
- `<meta itemprop="dateModified">` - Last modified date
- `<div itemprop="articleBody">` - Main content

The system will automatically:
- Extract title, dates, and excerpt from HTML
- Generate SEO-friendly slug from title
- Create JSON-LD schema
- Set canonical URL (self-canonicalization by default)

### SEO Features

The system provides comprehensive SEO optimization:

1. **Meta Tags**: Title, description, keywords
2. **JSON-LD Schema**: Automatic generation of schema.org Article markup
3. **Canonical URLs**: Self-canonicalization or custom URLs
4. **Descriptive Slugs**: Auto-generated from title, unique
5. **SEO Scoring**: Real-time analysis with recommendations
6. **Open Graph**: Automatic OG tags for social sharing
7. **Twitter Cards**: Enhanced Twitter sharing

### Maintenance Automation

The system automatically cleans up old articles based on your settings:

- **Daily Schedule**: Runs every day at 2 AM
- **Deletion Rules**:
  1. Delete articles older than `MAINTENANCE_DAYS_THRESHOLD`
  2. If total articles still exceed `MAINTENANCE_MAX_ARTICLES`, delete oldest articles
- **Manual Trigger**: Run maintenance anytime from admin panel or CLI

### API Integration with React/TypeScript

The system provides a complete REST API for frontend integration:

```typescript
// Example React component
import React, { useEffect, useState } from 'react';
import { Article } from './types';

const ArticleList: React.FC = () => {
  const [articles, setArticles] = useState<Article[]>([]);
  const [page, setPage] = useState(1);

  useEffect(() => {
    fetch(`/api/articles?page=${page}`)
      .then(res => res.json())
      .then(data => setArticles(data.data.articles));
  }, [page]);

  return (
    <div>
      {articles.map(article => (
        <ArticleCard key={article.id} article={article} />
      ))}
    </div>
  );
};
```

## CLI Commands

The package includes a powerful CLI:

```bash
# Initialize database and create admin
ams-cli init-db

# Create admin user
ams-cli create-admin

# List all articles
ams-cli list-articles

# Delete article by ID
ams-cli delete-article 123

# Run maintenance manually
ams-cli run-maintenance

# Export all articles to JSON
ams-cli export-articles -o backup.json
```

## Project Structure

```
article_management/
├── __init__.py          # Application factory
├── config.py            # Configuration classes
├── models.py            # Database models
├── seo_utils.py         # SEO utilities
├── html_parser.py       # HTML content parser
├── forms.py             # WTForms definitions
├── decorators.py        # Custom decorators
├── cli.py               # CLI commands
├── routes/
│   ├── __init__.py
│   ├── main.py          # Public routes
│   ├── admin.py         # Admin routes
│   ├── auth.py          # Authentication routes
│   └── api.py           # API endpoints
├── templates/           # Jinja2 templates
│   ├── base.html
│   ├── index.html
│   ├── article_detail.html
│   ├── auth/
│   └── admin/
├── static/
│   ├── css/style.css
│   └── js/main.js
└── wsgi.py              # WSGI entry point
```

## Database Schema

### Main Tables

- **users**: User accounts with authentication
- **articles**: Article content with SEO fields
- **comments**: Threaded comments (integrated with rcomments)
- **likes**: User likes/dislikes tracking
- **maintenance_settings**: Maintenance configuration

### Relationships
- User → Comments (one-to-many)
- User → Likes (one-to-many)
- Article → Comments (one-to-many, cascade delete)
- Article → Likes (one-to-many, cascade delete)
- Comment → Replies (self-referential)

## Deployment

### Production Configuration

1. **Environment Setup**:
```bash
export FLASK_ENV=production
export SECRET_KEY=your-very-secure-secret-key
export DATABASE_URL=postgresql://user:pass@host:5432/db
```

2. **Use a Production WSGI Server**:
```bash
# Using Gunicorn
pip install gunicorn
gunicorn -w 4 "article_management.wsgi:app" -b 0.0.0.0:8000
```

3. **Set up Systemd service** (Linux):
```ini
[Unit]
Description=Article Management System
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/app
Environment="PATH=/path/to/venv/bin"
EnvironmentFile=/path/to/.env
ExecStart=/path/to/venv/bin/gunicorn -w 4 "article_management.wsgi:app" -b 127.0.0.1:8000

[Install]
WantedBy=multi-user.target
```

4. **Nginx Configuration**:
```nginx
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
```

### Database Migrations

```bash
# Initialize migrations
flask db init

# Create migration
flask db migrate -m "Description"

# Apply migration
flask db upgrade
```

## Testing

Run tests with pytest:

```bash
pytest tests/
```

## Security Features

- Password hashing with werkzeug
- CSRF protection with Flask-WTF
- SQL injection prevention with SQLAlchemy
- XSS protection in templates
- Authentication required for admin routes
- Role-based access control (admin/user)
- Secure session management

## Extending the Package

### Custom Templates

Override templates by creating a `templates/` directory and setting `TEMPLATES_PATH` in config.

### Custom Static Files

Add custom CSS/JS by placing files in `static/` directory.

### Adding New Routes

Create a new blueprint in `routes/` and register it in `__init__.py`.

## Troubleshooting

### Common Issues

1. **Database connection error**:
   - Check PostgreSQL is running
   - Verify credentials in `DATABASE_URL`
   - Ensure database exists

2. **Template not found**:
   - Check Flask can find the templates directory
   - Verify package installation with `pip install -e .`

3. **Static files not loading**:
   - Ensure `static/` folder exists
   - Check file permissions

4. **Migrations fail**:
   - Ensure database user has proper privileges
   - Check Flask-Migrate is installed



## License

MIT License - see LICENSE file for details


## Changelog

### v1.0.0
- Initial release
- Full CRUD operations for articles
- SEO optimization with schema.org
- HTML import with automatic parsing
- Admin dashboard
- User authentication
- Comments system (rcomments integration)
- Likes/dislikes
- Maintenance automation
- REST API for frontend integration
- Responsive Bootstrap 5 UI
- CLI tools
