mirror of
https://github.com/mudabbir-ahmad/Media-Aggregation-and-Sorting-System.git
synced 2026-10-07 19:40:20 +00:00
feat: update backend URL and Google client IDs to use environment variables; add .env.example.txt
This commit is contained in:
1 parent
08bfd1168e
commit
f83edfa12a
5 files changed
+86
-259
No files matched your search
@@ -0,0 +1,4 @@
|
|||||||
|
EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID=
|
||||||
|
EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID=
|
||||||
|
EXPO_PUBLIC_BACKEND_URL=http://localhost:3001
|
||||||
|
|
||||||
@@ -9,3 +9,5 @@
|
|||||||
*.log
|
*.log
|
||||||
*.lock
|
*.lock
|
||||||
*.tmp
|
*.tmp
|
||||||
|
.env
|
||||||
|
!.env.example.txt
|
||||||
@@ -1,277 +1,97 @@
|
|||||||
# Media Aggregation and Sorting System
|
# Media Aggregation and Sorting System
|
||||||
|
This is my final-year mobile app project.
|
||||||
|
|
||||||
A React Native/Expo application that aggregates photos and videos from multiple sources (Google Photos, iCloud, and Network-Attached Storage) into a unified photo library.
|
It is an Expo/React Native app that pulls media from multiple sources (device storage, Google Photos picker flow, and NAS) and shows everything in one timeline-style view.
|
||||||
|
|
||||||
## Features
|
## What This Project Does
|
||||||
|
|
||||||
### Core Functionality
|
- Local user accounts (register/login)
|
||||||
- **User Authentication**: Local account creation and login with SQLite database storage
|
- Local SQLite database on-device (`PhotosApp.db`)
|
||||||
- **Multi-Service Integration**:
|
- Service onboarding for:
|
||||||
- 🔵 **Google Photos**: OAuth2 integration for Google Photos API
|
- Google Photos
|
||||||
- 🍎 **iCloud Photos**: Apple iCloud account support (placeholder)
|
- NAS
|
||||||
- 💾 **NAS Storage**: SFTP connection to Ubuntu servers for photo/video access
|
- iCloud placeholder
|
||||||
|
- Unified media view with source badges
|
||||||
- **Onboarding Flow**:
|
- Collections/albums screen
|
||||||
- Service selection (enable 1-3 services)
|
- Search screen
|
||||||
- Service configuration with credentials
|
- Settings screen for theme, services, and backup options
|
||||||
- Default service selection for uploads
|
|
||||||
|
|
||||||
- **Photo Gallery**:
|
## Current Architecture
|
||||||
- Unified photo library view combining all services
|
|
||||||
- Google Photos-styled grid layout
|
|
||||||
- Modal image viewer with metadata display
|
|
||||||
- Support for photos and videos
|
|
||||||
|
|
||||||
### Architecture
|
### App entry and navigation
|
||||||
|
|
||||||
#### Database Schema
|
- Entrypoint is `App.js`
|
||||||
- **users**: User account storage (username, email, password)
|
- `App.js` initializes the database, then mounts navigation
|
||||||
- **linked_accounts**: External service credentials and configurations
|
- Stack flow:
|
||||||
- **media**: Photo/video metadata from all sources
|
- `Login`
|
||||||
- **sync_logs**: Sync operation history and status
|
- `Register`
|
||||||
|
- `Onboarding`
|
||||||
|
- `MainTabs`
|
||||||
|
- `Settings`
|
||||||
|
- Bottom tabs in `MainTabs`:
|
||||||
|
- `Library` (`HomeScreen`)
|
||||||
|
- `Search` (`SearchScreen`)
|
||||||
|
- `Collections` (`AlbumsScreen`)
|
||||||
|
|
||||||
#### Authentication Services
|
### Data layer
|
||||||
All authentication services follow the `AuthServiceBase` interface for easy interchangeability:
|
|
||||||
|
|
||||||
1. **GoogleAUTH**: OAuth2 authentication with Google Photos API
|
Database setup lives in `src/services/DatabaseService.js`.
|
||||||
2. **IOSAUTH**: Apple iCloud authentication (currently placeholder)
|
|
||||||
3. **NASAUTH**: SFTP connection to Ubuntu servers via SSH2
|
|
||||||
|
|
||||||
#### Navigation Flow
|
Tables currently used:
|
||||||
```
|
- `users`
|
||||||
Login/Register → Onboarding (Service Setup) → Home (Photo Gallery)
|
- `linked_accounts`
|
||||||
```
|
- `media`
|
||||||
|
|
||||||
|
Passwords are hashed with SHA-256 via `src/services/CredentialEncryption.js`.
|
||||||
|
Linked account payloads are stored as Base64-encoded JSON strings.
|
||||||
|
|
||||||
|
### Service/auth layer
|
||||||
|
|
||||||
|
Auth services are in `src/AUTH/`:
|
||||||
|
- `GoogleAUTH.js`
|
||||||
|
- `NASAUTH.js`
|
||||||
|
- `IOSAUTH.js` (placeholder)
|
||||||
|
|
||||||
|
Common interface base: `src/AUTH/AuthServiceBase.js`.
|
||||||
|
|
||||||
|
API client wrappers are in `src/API/`.
|
||||||
|
|
||||||
|
### Backend (NAS side)
|
||||||
|
|
||||||
|
There is a separate Node/Express backend in `ServerFiles/server.js`.
|
||||||
|
|
||||||
|
It handles NAS connection and file operations for the mobile app.
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```text
|
||||||
Media-Aggregation-and-Sorting-System/
|
Media-Aggregation-and-Sorting-System/
|
||||||
|
├── App.js
|
||||||
|
├── app.json
|
||||||
|
├── package.json
|
||||||
├── src/
|
├── src/
|
||||||
|
│ ├── API/
|
||||||
│ ├── AUTH/
|
│ ├── AUTH/
|
||||||
│ │ ├── AuthServiceBase.js # Abstract auth service interface
|
|
||||||
│ │ ├── GoogleAUTH.js # Google Photos authentication
|
|
||||||
│ │ ├── IOSAUTH.js # iCloud authentication
|
|
||||||
│ │ └── NASAUTH.js # NAS SFTP authentication
|
|
||||||
│ ├── screens/
|
|
||||||
│ │ ├── LoginScreen.js # Login form
|
|
||||||
│ │ ├── RegisterScreen.js # Registration form
|
|
||||||
│ │ ├── OnboardingScreen.js # Service setup wizard
|
|
||||||
│ │ └── HomeScreen.js # Main photo gallery
|
|
||||||
│ ├── services/
|
|
||||||
│ │ └── DatabaseService.js # SQLite database operations
|
|
||||||
│ ├── components/
|
│ ├── components/
|
||||||
│ └── API/
|
│ ├── screens/
|
||||||
├── App.js # Navigation setup
|
│ └── services/
|
||||||
├── app.json # Expo configuration
|
├── ServerFiles/
|
||||||
├── package.json # Dependencies
|
│ ├── server.js
|
||||||
└── README.md
|
│ └── package.json
|
||||||
|
└── TEST/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Installation
|
## Running the Project
|
||||||
|
Useful scripts:
|
||||||
### Prerequisites
|
```bash
|
||||||
- Node.js and npm
|
expo run:android
|
||||||
- Expo CLI: `npm install -g expo-cli`
|
|
||||||
- iOS Simulator or Android Emulator (or physical device with Expo Go)
|
|
||||||
|
|
||||||
### Setup Steps
|
|
||||||
|
|
||||||
1. **Clone and Install Dependencies**
|
|
||||||
```bash
|
|
||||||
cd Media-Aggregation-and-Sorting-System
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Start the Development Server**
|
|
||||||
```bash
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Run on Device/Emulator**
|
|
||||||
- iOS: Press `i` in the terminal
|
|
||||||
- Android: Press `a` in the terminal
|
|
||||||
- Physical Device: Scan QR code with Expo Go app
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Creating an Account
|
|
||||||
1. Open the app → Select "Register here"
|
|
||||||
2. Enter username, email, and password (min 6 characters)
|
|
||||||
3. Confirm password and create account
|
|
||||||
|
|
||||||
### Login
|
|
||||||
1. Enter registered email and password
|
|
||||||
2. Click "Login"
|
|
||||||
|
|
||||||
### Onboarding (Service Configuration)
|
|
||||||
**Step 1: Select Services**
|
|
||||||
- Toggle which services to enable (1-3 maximum)
|
|
||||||
- Google Photos, iCloud, and/or NAS
|
|
||||||
|
|
||||||
**Step 2: Configure Services**
|
|
||||||
- **Google Photos**: Tap to authenticate with Google (OAuth flow)
|
|
||||||
- **iCloud**: Tap to authenticate with Apple (OAuth flow)
|
|
||||||
- **NAS**: Enter connection details:
|
|
||||||
- Server address (IP or hostname)
|
|
||||||
- SSH port (default: 22)
|
|
||||||
- Username
|
|
||||||
- Password
|
|
||||||
- Photos folder path
|
|
||||||
- Test connection before proceeding
|
|
||||||
|
|
||||||
**Step 3: Choose Default Service**
|
|
||||||
- Select which service to use by default for uploads
|
|
||||||
|
|
||||||
### Photo Gallery
|
|
||||||
- View all photos/videos from connected services
|
|
||||||
- Service badges at top show connected accounts
|
|
||||||
- ★ indicates the default service
|
|
||||||
- Tap any photo to view in enlarged modal
|
|
||||||
- Modal shows metadata: title, description, source, type, date
|
|
||||||
|
|
||||||
## API Integration (TODO)
|
|
||||||
|
|
||||||
### Google Photos Implementation
|
|
||||||
- Replace placeholder `authenticate()` with actual Google Sign-In
|
|
||||||
- Implement OAuth2 token exchange
|
|
||||||
- Add `/photoslibrary/v1/mediaItems:search` API calls
|
|
||||||
- Handle pagination and filtering
|
|
||||||
|
|
||||||
### iCloud Implementation
|
|
||||||
- Integrate Apple Sign-In
|
|
||||||
- Implement CloudKit API for photo access
|
|
||||||
- Handle iCloud authentication
|
|
||||||
|
|
||||||
### NAS Implementation
|
|
||||||
- Replace SSH2 placeholders with actual library implementation
|
|
||||||
- Implement SFTP file listing and download
|
|
||||||
- Add file upload functionality
|
|
||||||
- Handle directory navigation
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Environment Variables (Optional)
|
|
||||||
Create a `.env` file for sensitive configuration:
|
|
||||||
```env
|
|
||||||
GOOGLE_CLIENT_ID=your_client_id
|
|
||||||
GOOGLE_CLIENT_SECRET=your_client_secret
|
|
||||||
NAS_DEFAULT_PORT=22
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Database
|
|
||||||
- SQLite database is automatically created on first run
|
|
||||||
- Location: Device's app-specific directory
|
|
||||||
- Filename: `PhotosApp.db`
|
|
||||||
|
|
||||||
## Authentication Service Pattern
|
### NAS backend
|
||||||
|
|
||||||
Each service implements the same interface:
|
```bash
|
||||||
|
cd ./ServerFiles
|
||||||
```javascript
|
npm i
|
||||||
class AuthService extends AuthServiceBase {
|
|
||||||
async authenticate(credentials) { }
|
|
||||||
async getAccessToken() { }
|
|
||||||
async refreshToken() { }
|
|
||||||
async revokeAccess() { }
|
|
||||||
async getUserInfo() { }
|
|
||||||
// Service-specific methods
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Easy Interchangeability
|
|
||||||
To swap or extend authentication:
|
|
||||||
|
|
||||||
1. Create new class extending `AuthServiceBase`
|
|
||||||
2. Implement all abstract methods
|
|
||||||
3. Update the service type in `DatabaseService.linkAccount()`
|
|
||||||
4. Update `OnboardingScreen` UI if needed
|
|
||||||
|
|
||||||
## Data Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
Login/Register
|
|
||||||
↓
|
|
||||||
Authentication → Save to SQLite
|
|
||||||
↓
|
|
||||||
Onboarding → Service Selection
|
|
||||||
↓
|
|
||||||
Service Auth → Store Credentials
|
|
||||||
↓
|
|
||||||
Home Screen → Fetch from Services
|
|
||||||
↓
|
|
||||||
Display in Gallery
|
|
||||||
```
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
⚠️ **Current Implementation Warnings**:
|
|
||||||
- Passwords stored in plain text in SQLite (development only)
|
|
||||||
- NAS passwords stored in plain text (development only)
|
|
||||||
- OAuth tokens not persisted securely
|
|
||||||
|
|
||||||
**For Production**:
|
|
||||||
- Use secure storage (Keychain/Keystore)
|
|
||||||
- Encrypt sensitive data in database
|
|
||||||
- Implement token refresh and expiration
|
|
||||||
- Use OAuth for all services
|
|
||||||
- Never store plain-text passwords
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
### Core
|
|
||||||
- `react`: 19.1.0
|
|
||||||
- `react-native`: 0.81.5
|
|
||||||
- `expo`: ~54.0.31
|
|
||||||
|
|
||||||
### Navigation
|
|
||||||
- `@react-navigation/native`: ^6.1.17
|
|
||||||
- `@react-navigation/native-stack`: ^6.9.26
|
|
||||||
- `react-native-screens`: ^3.31.1
|
|
||||||
- `react-native-safe-area-context`: ^4.10.5
|
|
||||||
- `react-native-gesture-handler`: ^2.16.1
|
|
||||||
|
|
||||||
### Database & Storage
|
|
||||||
- `react-native-sqlite-storage`: ^6.0.0
|
|
||||||
- `expo-file-system`: ~17.0.1
|
|
||||||
- `expo-media-library`: ~15.9.0
|
|
||||||
|
|
||||||
### Network
|
|
||||||
- `ssh2`: ^1.15.0
|
|
||||||
- `react-native-ssh2`: ^1.0.0
|
|
||||||
|
|
||||||
### Media
|
|
||||||
- `expo-image-picker`: ~14.7.1
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Database Initialization Error
|
|
||||||
```
|
|
||||||
Solution: Clear app cache/reinstall
|
|
||||||
npx expo prebuild --clean
|
|
||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
### Navigation Issues
|
|
||||||
Ensure all screens are properly exported and imported in App.js
|
|
||||||
|
|
||||||
### Service Connection Failures
|
|
||||||
- Check network connectivity
|
|
||||||
- Verify API credentials
|
|
||||||
- Check NAS server accessibility (port 22 open)
|
|
||||||
- Review console logs for detailed error messages
|
|
||||||
|
|
||||||
## Future Enhancements
|
|
||||||
|
|
||||||
- [ ] Implement actual Google Photos API integration
|
|
||||||
- [ ] Implement actual iCloud Photos integration
|
|
||||||
- [ ] Complete SFTP functionality for NAS
|
|
||||||
- [ ] Photo upload to default service
|
|
||||||
- [ ] Photo search and filtering
|
|
||||||
- [ ] Album management
|
|
||||||
- [ ] Automatic sync scheduling
|
|
||||||
- [ ] Cloud backup
|
|
||||||
- [ ] Photo sharing features
|
|
||||||
- [ ] Advanced metadata editing
|
|
||||||
- [ ] Duplicate detection
|
|
||||||
- [ ] Smart album creation
|
|
||||||
- [ ] Facial recognition (optional)
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
const DEFAULT_BACKEND_URL = 'http://192.168.1.100:3001';
|
const DEFAULT_BACKEND_URL = process.env.EXPO_PUBLIC_BACKEND_URL || 'http://localhost:3001';
|
||||||
|
|
||||||
class NASAPI {
|
class NASAPI {
|
||||||
constructor(backendUrl = DEFAULT_BACKEND_URL) {
|
constructor(backendUrl = DEFAULT_BACKEND_URL) {
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ import { logError } from '../services/ErrorHandler';
|
|||||||
|
|
||||||
WebBrowser.maybeCompleteAuthSession();
|
WebBrowser.maybeCompleteAuthSession();
|
||||||
|
|
||||||
const ANDROID_CLIENT_ID = '313090284964-018uf4v1bmmrra09lvmpnuug2qs09047.apps.googleusercontent.com';
|
const ANDROID_CLIENT_ID = process.env.EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID || '';
|
||||||
const IOS_CLIENT_ID = '313090284964-luka809nuc66bb4cg4gameovtqg8uoj1.apps.googleusercontent.com';
|
const IOS_CLIENT_ID = process.env.EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID || '';
|
||||||
|
const ACTIVE_CLIENT_ID = ANDROID_CLIENT_ID || IOS_CLIENT_ID;
|
||||||
|
|
||||||
const GOOGLE_DISCOVERY = {
|
const GOOGLE_DISCOVERY = {
|
||||||
authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
|
authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
|
||||||
@@ -39,7 +40,7 @@ class GoogleAUTH extends AuthServiceBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async authenticate() {
|
async authenticate() {
|
||||||
if (ANDROID_CLIENT_ID === 'REPLACE_WITH_ANDROID_CLIENT_ID.apps.googleusercontent.com') {
|
if (!ACTIVE_CLIENT_ID) {
|
||||||
console.warn('Google Auth: no Android client ID — using placeholder mode');
|
console.warn('Google Auth: no Android client ID — using placeholder mode');
|
||||||
this.accessToken = 'placeholder_google_token_' + Date.now();
|
this.accessToken = 'placeholder_google_token_' + Date.now();
|
||||||
this.refreshToken = 'placeholder_refresh_' + Date.now();
|
this.refreshToken = 'placeholder_refresh_' + Date.now();
|
||||||
@@ -57,7 +58,7 @@ class GoogleAUTH extends AuthServiceBase {
|
|||||||
console.log('Requesting scopes:', SCOPES.join(' '));
|
console.log('Requesting scopes:', SCOPES.join(' '));
|
||||||
|
|
||||||
const authRequest = new AuthSession.AuthRequest({
|
const authRequest = new AuthSession.AuthRequest({
|
||||||
clientId: ANDROID_CLIENT_ID,
|
clientId: ACTIVE_CLIENT_ID,
|
||||||
scopes: SCOPES,
|
scopes: SCOPES,
|
||||||
redirectUri: REDIRECT_URI,
|
redirectUri: REDIRECT_URI,
|
||||||
responseType: AuthSession.ResponseType.Code,
|
responseType: AuthSession.ResponseType.Code,
|
||||||
@@ -77,7 +78,7 @@ class GoogleAUTH extends AuthServiceBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tokenBody = new URLSearchParams({
|
const tokenBody = new URLSearchParams({
|
||||||
client_id: ANDROID_CLIENT_ID,
|
client_id: ACTIVE_CLIENT_ID,
|
||||||
code: result.params.code,
|
code: result.params.code,
|
||||||
code_verifier: authRequest.codeVerifier,
|
code_verifier: authRequest.codeVerifier,
|
||||||
grant_type: 'authorization_code',
|
grant_type: 'authorization_code',
|
||||||
@@ -135,7 +136,7 @@ class GoogleAUTH extends AuthServiceBase {
|
|||||||
|
|
||||||
async refreshAccessToken() {
|
async refreshAccessToken() {
|
||||||
const body = new URLSearchParams({
|
const body = new URLSearchParams({
|
||||||
client_id: ANDROID_CLIENT_ID,
|
client_id: ACTIVE_CLIENT_ID,
|
||||||
refresh_token: this.refreshToken,
|
refresh_token: this.refreshToken,
|
||||||
grant_type: 'refresh_token',
|
grant_type: 'refresh_token',
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user