Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions YOUTUBE_OAUTH_SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# YouTube OAuth Setup Guide
*Spoken Tutorial – YouTube Upload Integration*

This document explains how to create and configure Google OAuth credentials required for uploading videos to YouTube from the Spoken Tutorial website.

The YouTube Data API does **not** allow uploads using a simple API key. Uploading requires OAuth 2.0 credentials because it modifies a user's YouTube channel.

---

## 1. Create a Google Cloud Project

1. Visit: https://console.cloud.google.com/
2. Click **New Project**
3. Name it something like:

```
spoken-youtube-upload
```

4. Create the project.

![Create Project](youtube_auth_setup_screenshots/create%20project.png)
---

## 2. Enable YouTube Data API v3

1. Inside the project, go to **APIs & Services → Library**
2. Search for **YouTube Data API v3**
3. Click **Enable**

![Enable YouTube API](youtube_auth_setup_screenshots/enable-youtube-api.png)

---

## 3. Configure OAuth Consent Screen

1. Go to **APIs & Services → OAuth consent screen → Get Started**
2. Fill the basic details:
- App name: `Spoken YouTube Uploader`
- User support email: your email
3. Choose **External**
4. Save and continue with defaults.


![Consent Screen](youtube_auth_setup_screenshots/oauth-consent.png)

If the app is in **Testing** mode, go to **Audience** and add your email under **Test Users**.


![Test Users](youtube_auth_setup_screenshots/test-users.png)

---

## 4. Create OAuth Client ID

1. Go to **APIs & Services → Credentials**
2. Click **Create Credentials → OAuth client ID**
3. Application type: **Web application**
4. Name: `Django YouTube Uploader`
5. Add the following **Authorized redirect URIs**:

```
http://127.0.0.1:8000/youtube/oauth2callback/
http://localhost:8000/youtube/oauth2callback/
https://spoken-tutorial.org/youtube/oauth2callback/
```

6. Save.

![OAuth Client](youtube_auth_setup_screenshots/oauth-client.png)

---

## 5. Download Client Secret

1. In the Credentials list, click the download icon for the OAuth client.
2. Rename the file to:

```
client_secret.json
```

3. Place it in:

```
spoken-website/youtube/client_secret.json
```

This file is required for authentication and **must not be committed to version control**.

![Client Secret](youtube_auth_setup_screenshots/client-secret.png)

---

## 6. First-Time Authorization

1. Open the upload page:

```
/software-training/add-youtube-video/
```

2. If not authorized, the page will show:

> "YouTube credentials not found. Click here to authorize."

3. Click the link and sign in with the Google account that owns the YouTube channel.
4. Grant access.
5. You will be redirected back to the site.

This is a one-time step. After authorization, uploads work normally.

---

## Notes

- Each environment (local, staging, production) must have its redirect URI registered.
- Only users added as **Test Users** can authorize while the app is unverified.
- Upload permissions inside the site are controlled by:

```python
# spoken/config.py
YOUTUBE_UPLOAD_ROLES = ["YouTube Admin"]
```

Only users in these roles can access the upload feature.

---
53 changes: 52 additions & 1 deletion events/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from django.http import HttpResponseForbidden, HttpResponseBadRequest
from .models import StudentBatch
from django.urls import reverse
from django import forms

def get_batches(request):
school_id = request.GET.get('school_id')
Expand Down Expand Up @@ -89,6 +90,7 @@ def get_batches(request):
from mdldjango.get_or_create_participant import encript_password
from .helpers import send_bulk_student_reset_mail, get_fossmdlcourse
from .certificates import *
from youtube.utils import user_can_upload_to_youtube

def can_clone_training(training):
if training.tdate > datetime.datetime.strptime('01-02-2015', "%d-%m-%Y").date() and training.organiser.academic.institution_type.name != 'School':
Expand Down Expand Up @@ -622,6 +624,7 @@ def events_dashboard(request):
'rp_workshop_notification': rp_workshop_notification,
'rp_training_notification': rp_training_notification,
'invigilator_test_notification': invigilator_test_notification,
'can_upload_youtube': user_can_upload_to_youtube(user),
}
return render(request, 'events/templates/events_dashboard.html',
context)
Expand Down Expand Up @@ -3348,4 +3351,52 @@ def get_schools(request):
return JsonResponse([])



class YouTubeUploadForm(forms.Form):
"""Form for uploading YouTube videos"""
video = forms.FileField(
label='Video File',
widget=forms.FileInput(attrs={'class': 'form-control'})
)
title = forms.CharField(
label='Title',
max_length=200,
widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter video title'})
)
description = forms.CharField(
label='Description',
widget=forms.Textarea(attrs={'class': 'form-control', 'placeholder': 'Enter video description'})
)
privacy_status = forms.ChoiceField(
label='Privacy Status',
choices=[
('public', 'Public'),
('unlisted', 'Unlisted'),
('private', 'Private'),
],
widget=forms.Select(attrs={'class': 'form-control'})
)


def add_youtube_video(request):
"""
View for uploading YouTube videos with title, description, and privacy settings.
"""
context = {}
template = 'youtube/templates/add_youtube_video.html'

if request.method == 'GET':
# Display empty form
form = YouTubeUploadForm()
context['form'] = form

elif request.method == 'POST':
# Handle form submission
form = YouTubeUploadForm(request.POST, request.FILES)
context['form'] = form

if form.is_valid():
# Backend processing would happen here (currently placeholder)
messages.success(request, 'Video upload initiated successfully!')
return HttpResponseRedirect('/software-training/')

return render(request, template, context)
10 changes: 10 additions & 0 deletions static/events/templates/events_dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,16 @@ <h5>Online Assessment Test</h5>
</div>
{% endif %}

{% if can_upload_youtube %}
<div class="panel panel-primary">
<div class="panel-heading panel-heading-notif">YouTube</div>
<div class="panel-body">
<ul>
<li><a href="/software-training/add-youtube-video/">Upload Video</a></li>
</ul>
</div>
</div>
{% endif %}

{% if user|is_invigilator %}
<div class="panel panel-primary">
Expand Down
Loading