migrate Swagger 2.0 spec to OpenAPI 3.0.0
This commit is contained in:
parent
6cb3482ceb
commit
3e9e6f2f14
19 changed files with 1224 additions and 15698 deletions
|
@ -183,9 +183,8 @@ See [ARCHITECTURE.md](/ARCHITECTURE.md) for a more detailed explanation of the a
|
|||
#### Backend
|
||||
|
||||
* REST API:
|
||||
* Quick Start: [/support/doc/api/quickstart.md](/support/doc/api/quickstart.md)
|
||||
* Swagger/OpenAPI schema: [/support/doc/api/openapi.yaml](/support/doc/api/openapi.yaml)
|
||||
* HTML explorer: [/support/doc/api/html/index.html](https://htmlpreview.github.io/?https://github.com/Chocobozzz/PeerTube/blob/develop/support/doc/api/html/index.html)
|
||||
* OpenAPI 3.0.0 schema: [/support/doc/api/openapi.yaml](/support/doc/api/openapi.yaml)
|
||||
* HTML explorer: [docs.joinpeertube.org/api.html](http://docs.joinpeertube.org/api.html)
|
||||
* Servers communicate with each other with [Activity
|
||||
Pub](https://www.w3.org/TR/activitypub/).
|
||||
* Each server has its own users who query it (search videos, query where the
|
||||
|
|
14
package.json
14
package.json
|
@ -49,14 +49,12 @@
|
|||
"create-import-video-file-job": "node ./dist/scripts/create-import-video-file-job.js",
|
||||
"test": "scripty",
|
||||
"help": "scripty",
|
||||
"generate-api-doc": "scripty",
|
||||
"generate-cli-doc": "scripty",
|
||||
"parse-log": "node ./dist/scripts/parse-log.js",
|
||||
"prune-storage": "node ./dist/scripts/prune-storage.js",
|
||||
"optimize-old-videos": "node ./dist/scripts/optimize-old-videos.js",
|
||||
"postinstall": "cd client && yarn install --pure-lockfile",
|
||||
"tsc": "tsc",
|
||||
"spectacle-docs": "node_modules/spectacle-docs/bin/spectacle.js",
|
||||
"commander": "commander",
|
||||
"ng": "ng",
|
||||
"nodemon": "nodemon",
|
||||
|
@ -72,13 +70,21 @@
|
|||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged && ./scripts/openapi-peertube-version.sh"
|
||||
"pre-commit": "./scripts/openapi-peertube-version.sh && lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.scss": [
|
||||
"sass-lint -c client/.sass-lint.yml",
|
||||
"git add"
|
||||
],
|
||||
"support/doc/api/*.yaml": [
|
||||
"node ./node_modules/swagger-cli/bin/swagger-cli.js validate support/doc/api/openapi.yaml",
|
||||
"git add"
|
||||
],
|
||||
"server/tools/README.md": [
|
||||
"npm run generate-cli-doc",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"resolutions": {
|
||||
|
@ -200,8 +206,8 @@
|
|||
"nodemon": "^1.11.0",
|
||||
"sass-lint": "^1.12.1",
|
||||
"source-map-support": "^0.5.0",
|
||||
"spectacle-docs": "^1.0.2",
|
||||
"supertest": "^3.0.0",
|
||||
"swagger-cli": "^2.2.0",
|
||||
"ts-node": "7.0.1",
|
||||
"tslint": "^5.7.0",
|
||||
"tslint-config-standard": "^8.0.1",
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
npm run spectacle-docs -- -t support/doc/api/html support/doc/api/openapi.yaml
|
|
@ -1,7 +0,0 @@
|
|||
parameters:
|
||||
name:
|
||||
name: name
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
description: 'The name of the account (chocobozzz or chocobozzz@peertube.cpy.re for example)'
|
|
@ -1,23 +0,0 @@
|
|||
parameters:
|
||||
start:
|
||||
name: start
|
||||
in: query
|
||||
required: false
|
||||
type: number
|
||||
description: 'Offset'
|
||||
count:
|
||||
name: count
|
||||
in: query
|
||||
required: false
|
||||
type: number
|
||||
description: 'Number of items'
|
||||
sort:
|
||||
name: sort
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
description: 'Sort column (-createdAt for example)'
|
||||
|
||||
responses:
|
||||
emptySuccess:
|
||||
description: 'Successful operation'
|
File diff suppressed because it is too large
Load diff
|
@ -1,242 +0,0 @@
|
|||
$(function() {
|
||||
// $(document).foundation();
|
||||
|
||||
var $sidebar = $('#sidebar');
|
||||
if ($sidebar.length) {
|
||||
var $docs = $('#docs');
|
||||
var $nav = $sidebar.find('nav');
|
||||
|
||||
//
|
||||
// Setup sidebar navigation
|
||||
var traverse = new Traverse($nav, {
|
||||
threshold: 10,
|
||||
barOffset: $sidebar.position().top
|
||||
});
|
||||
|
||||
$nav.on('update.traverse', function(event, element) {
|
||||
$nav.find('section').removeClass('expand');
|
||||
var $section = element.parents('section:first');
|
||||
if ($section.length) {
|
||||
$section.addClass('expand');
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
// Bind the drawer layout
|
||||
var $drawerLayout = $('.drawer-layout'),
|
||||
$drawer = $drawerLayout.find('.drawer'),
|
||||
closeDrawer = function() {
|
||||
$drawer.removeClass('slide-right slide-left');
|
||||
$drawer.find('.drawer-overlay').remove();
|
||||
$drawerLayout.removeClass('drawer-open drawer-slide-left-large drawer-slide-right-large');
|
||||
return false;
|
||||
};
|
||||
|
||||
// Drawer open buttons
|
||||
$drawerLayout.find('[data-drawer-slide]').click(function(e) {
|
||||
var $this = $(this),
|
||||
direction = $this.data('drawer-slide');
|
||||
$drawerLayout.addClass('drawer-open');
|
||||
$drawer.addClass('slide-' + direction);
|
||||
|
||||
var $overlay = $('<a href="#" class="drawer-overlay"></a>')
|
||||
$drawer.append($overlay);
|
||||
$overlay.click(closeDrawer);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// Drawer close buttons
|
||||
$drawerLayout.find('[data-drawer-close]').click(closeDrawer);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates a new instance of Traverse.
|
||||
* @class
|
||||
* @fires Traverse#init
|
||||
* @param {Object} element - jQuery object to add the trigger to.
|
||||
* @param {Object} options - Overrides to the default plugin settings.
|
||||
*/
|
||||
function Traverse(element, options) {
|
||||
this.$element = element;
|
||||
this.options = $.extend({}, Traverse.defaults, this.$element.data(), options);
|
||||
|
||||
this._init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Default settings for plugin
|
||||
*/
|
||||
Traverse.defaults = {
|
||||
/**
|
||||
* Amount of time, in ms, the animated scrolling should take between locations.
|
||||
* @option
|
||||
* @example 500
|
||||
*/
|
||||
animationDuration: 500,
|
||||
/**
|
||||
* Animation style to use when scrolling between locations.
|
||||
* @option
|
||||
* @example 'ease-in-out'
|
||||
*/
|
||||
animationEasing: 'linear',
|
||||
/**
|
||||
* Number of pixels to use as a marker for location changes.
|
||||
* @option
|
||||
* @example 50
|
||||
*/
|
||||
threshold: 50,
|
||||
/**
|
||||
* Class applied to the active locations link on the traverse container.
|
||||
* @option
|
||||
* @example 'active'
|
||||
*/
|
||||
activeClass: 'active',
|
||||
/**
|
||||
* Allows the script to manipulate the url of the current page, and if supported, alter the history.
|
||||
* @option
|
||||
* @example true
|
||||
*/
|
||||
deepLinking: false,
|
||||
/**
|
||||
* Number of pixels to offset the scroll of the page on item click if using a sticky nav bar.
|
||||
* @option
|
||||
* @example 25
|
||||
*/
|
||||
barOffset: 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the Traverse plugin and calls functions to get equalizer functioning on load.
|
||||
* @private
|
||||
*/
|
||||
Traverse.prototype._init = function() {
|
||||
var id = this.$element[0].id, // || Foundation.GetYoDigits(6, 'traverse'),
|
||||
_this = this;
|
||||
this.$targets = $('[data-traverse-target]');
|
||||
this.$links = this.$element.find('a');
|
||||
this.$element.attr({
|
||||
'data-resize': id,
|
||||
'data-scroll': id,
|
||||
'id': id
|
||||
});
|
||||
this.$active = $();
|
||||
this.scrollPos = parseInt(window.pageYOffset, 10);
|
||||
|
||||
this._events();
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates an array of pixel values that are the demarcation lines between locations on the page.
|
||||
* Can be invoked if new elements are added or the size of a location changes.
|
||||
* @function
|
||||
*/
|
||||
Traverse.prototype.calcPoints = function(){
|
||||
var _this = this,
|
||||
body = document.body,
|
||||
html = document.documentElement;
|
||||
|
||||
this.points = [];
|
||||
this.winHeight = Math.round(Math.max(window.innerHeight, html.clientHeight));
|
||||
this.docHeight = Math.round(Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight));
|
||||
|
||||
this.$targets.each(function(){
|
||||
var $tar = $(this),
|
||||
pt = $tar.offset().top; // Math.round($tar.offset().top - _this.options.threshold);
|
||||
$tar.targetPoint = pt;
|
||||
_this.points.push(pt);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes events for Traverse.
|
||||
* @private
|
||||
*/
|
||||
Traverse.prototype._events = function() {
|
||||
var _this = this,
|
||||
$body = $('html, body'),
|
||||
opts = {
|
||||
duration: _this.options.animationDuration,
|
||||
easing: _this.options.animationEasing
|
||||
};
|
||||
|
||||
$(window).one('load', function(){
|
||||
_this.calcPoints();
|
||||
_this._updateActive();
|
||||
|
||||
$(this).resize(function(e) {
|
||||
_this.reflow();
|
||||
}).scroll(function(e) {
|
||||
_this._updateActive();
|
||||
});
|
||||
})
|
||||
|
||||
this.$element.on('click', 'a[href^="#"]', function(e) { //'click.zf.traverse'
|
||||
e.preventDefault();
|
||||
var arrival = this.getAttribute('href').replace(".", "\\."),
|
||||
scrollPos = $(arrival).offset().top - _this.options.barOffset; // - _this.options.threshold / 2 - _this.options.barOffset;
|
||||
|
||||
$body.stop(true).animate({
|
||||
scrollTop: scrollPos
|
||||
}, opts);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls necessary functions to update Traverse upon DOM change
|
||||
* @function
|
||||
*/
|
||||
Traverse.prototype.reflow = function(){
|
||||
this.calcPoints();
|
||||
this._updateActive();
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the visibility of an active location link,
|
||||
* and updates the url hash for the page, if deepLinking enabled.
|
||||
* @private
|
||||
* @function
|
||||
* @fires Traverse#update
|
||||
*/
|
||||
Traverse.prototype._updateActive = function(){
|
||||
var winPos = parseInt(window.pageYOffset, 10),
|
||||
curIdx;
|
||||
|
||||
if(winPos + this.winHeight === this.docHeight){ curIdx = this.points.length - 1; }
|
||||
else if(winPos < this.points[0]){ curIdx = 0; }
|
||||
else{
|
||||
var isDown = this.scrollPos < winPos,
|
||||
_this = this,
|
||||
curVisible = this.points.filter(function(p, i){
|
||||
return isDown ?
|
||||
p <= (winPos + _this.options.barOffset + _this.options.threshold) :
|
||||
(p - (_this.options.barOffset + _this.options.threshold)) <= winPos;
|
||||
// p <= (winPos - (offset - _this.options.threshold)) :
|
||||
// (p - (-offset + _this.options.threshold)) <= winPos;
|
||||
});
|
||||
curIdx = curVisible.length ? curVisible.length - 1 : 0;
|
||||
}
|
||||
|
||||
var $prev = this.$active;
|
||||
var $next = this.$links.eq(curIdx);
|
||||
this.$active.removeClass(this.options.activeClass);
|
||||
this.$active = $next.addClass(this.options.activeClass);
|
||||
|
||||
if(this.options.deepLinking){
|
||||
var hash = this.$active[0].getAttribute('href');
|
||||
if(window.history.pushState){
|
||||
window.history.pushState(null, null, hash);
|
||||
}else{
|
||||
window.location.hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
this.scrollPos = winPos;
|
||||
|
||||
// Fire event if the active element was changed
|
||||
var changed = $prev[0] !== $next[0];
|
||||
if (changed) {
|
||||
this.$element.trigger('update.traverse', [this.$active]);
|
||||
}
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
function Traverse(t,e){this.$element=t,this.options=$.extend({},Traverse.defaults,this.$element.data(),e),this._init()}$(function(){var t=$("#sidebar");if(t.length){$("#docs");var s=t.find("nav");new Traverse(s,{threshold:10,barOffset:t.position().top});s.on("update.traverse",function(t,e){s.find("section").removeClass("expand");var i=e.parents("section:first");i.length&&i.addClass("expand")});var a=$(".drawer-layout"),n=a.find(".drawer"),r=function(){return n.removeClass("slide-right slide-left"),n.find(".drawer-overlay").remove(),a.removeClass("drawer-open drawer-slide-left-large drawer-slide-right-large"),!1};a.find("[data-drawer-slide]").click(function(t){var e=$(this).data("drawer-slide");a.addClass("drawer-open"),n.addClass("slide-"+e);var i=$('<a href="#" class="drawer-overlay"></a>');return n.append(i),i.click(r),!1}),a.find("[data-drawer-close]").click(r)}}),Traverse.defaults={animationDuration:500,animationEasing:"linear",threshold:50,activeClass:"active",deepLinking:!1,barOffset:0},Traverse.prototype._init=function(){var t=this.$element[0].id;this.$targets=$("[data-traverse-target]"),this.$links=this.$element.find("a"),this.$element.attr({"data-resize":t,"data-scroll":t,id:t}),this.$active=$(),this.scrollPos=parseInt(window.pageYOffset,10),this._events()},Traverse.prototype.calcPoints=function(){var i=this,t=document.body,e=document.documentElement;this.points=[],this.winHeight=Math.round(Math.max(window.innerHeight,e.clientHeight)),this.docHeight=Math.round(Math.max(t.scrollHeight,t.offsetHeight,e.clientHeight,e.scrollHeight,e.offsetHeight)),this.$targets.each(function(){var t=$(this),e=t.offset().top;t.targetPoint=e,i.points.push(e)})},Traverse.prototype._events=function(){var s=this,a=$("html, body"),n={duration:s.options.animationDuration,easing:s.options.animationEasing};$(window).one("load",function(){s.calcPoints(),s._updateActive(),$(this).resize(function(t){s.reflow()}).scroll(function(t){s._updateActive()})}),this.$element.on("click",'a[href^="#"]',function(t){t.preventDefault();var e=this.getAttribute("href").replace(".","\\."),i=$(e).offset().top-s.options.barOffset;a.stop(!0).animate({scrollTop:i},n)})},Traverse.prototype.reflow=function(){this.calcPoints(),this._updateActive()},Traverse.prototype._updateActive=function(){var t,i=parseInt(window.pageYOffset,10);if(i+this.winHeight===this.docHeight)t=this.points.length-1;else if(i<this.points[0])t=0;else{var s=this.scrollPos<i,a=this,e=this.points.filter(function(t,e){return s?t<=i+a.options.barOffset+a.options.threshold:t-(a.options.barOffset+a.options.threshold)<=i});t=e.length?e.length-1:0}var n=this.$active,r=this.$links.eq(t);if(this.$active.removeClass(this.options.activeClass),this.$active=r.addClass(this.options.activeClass),this.options.deepLinking){var o=this.$active[0].getAttribute("href");window.history.pushState?window.history.pushState(null,null,o):window.location.hash=o}this.scrollPos=i,n[0]!==r[0]&&this.$element.trigger("update.traverse",[this.$active])};
|
2285
support/doc/api/html/stylesheets/foundation.css
vendored
2285
support/doc/api/html/stylesheets/foundation.css
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
@ -1,7 +0,0 @@
|
|||
parameters:
|
||||
id:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
type: number
|
||||
description: 'The user id'
|
|
@ -1,7 +0,0 @@
|
|||
parameters:
|
||||
id:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
description: 'The video channel id or uuid'
|
|
@ -1,13 +0,0 @@
|
|||
parameters:
|
||||
threadId:
|
||||
name: threadId
|
||||
in: path
|
||||
required: true
|
||||
type: number
|
||||
description: 'The thread id (root comment id)'
|
||||
commentId:
|
||||
name: threadId
|
||||
in: path
|
||||
required: true
|
||||
type: number
|
||||
description: 'The comment id'
|
|
@ -1,87 +0,0 @@
|
|||
parameters:
|
||||
id:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
type: string
|
||||
description: 'The video id or uuid'
|
||||
thumbnailfile:
|
||||
name: thumbnailfile
|
||||
in: formData
|
||||
type: file
|
||||
description: 'Video thumbnail file'
|
||||
previewfile:
|
||||
name: previewfile
|
||||
in: formData
|
||||
type: file
|
||||
description: 'Video preview file'
|
||||
category:
|
||||
name: category
|
||||
in: formData
|
||||
type: number
|
||||
description: 'Video category'
|
||||
licence:
|
||||
name: licence
|
||||
in: formData
|
||||
type: number
|
||||
description: 'Video licence'
|
||||
language:
|
||||
name: language
|
||||
in: formData
|
||||
type: string
|
||||
description: 'Video language'
|
||||
description:
|
||||
name: description
|
||||
in: formData
|
||||
type: string
|
||||
description: 'Video description'
|
||||
waitTranscoding:
|
||||
name: waitTranscoding
|
||||
in: formData
|
||||
type: boolean
|
||||
description: 'Whether or not we wait transcoding before publish the video'
|
||||
support:
|
||||
name: support
|
||||
in: formData
|
||||
type: string
|
||||
description: 'Text describing how to support the video uploader'
|
||||
nsfw:
|
||||
name: nsfw
|
||||
in: formData
|
||||
type: boolean
|
||||
description: 'Whether or not this video contains sensitive content'
|
||||
name:
|
||||
name: name
|
||||
in: formData
|
||||
type: string
|
||||
description: 'Video name'
|
||||
tags:
|
||||
name: tags
|
||||
in: formData
|
||||
type: string[]
|
||||
description: 'Video tags'
|
||||
commentsEnabled:
|
||||
name: commentsEnabled
|
||||
in: formData
|
||||
type: boolean
|
||||
description: 'Enable or disable comments for this video'
|
||||
privacy:
|
||||
name: privacy
|
||||
in: formData
|
||||
type: string
|
||||
enum: [Public, Unlisted]
|
||||
description: 'Video privacy'
|
||||
scheduleUpdate:
|
||||
name: scheduleUpdate
|
||||
in: formData
|
||||
required: false
|
||||
description: 'Schedule an update at a specific datetime'
|
||||
properties:
|
||||
updateAt:
|
||||
type: dateTime
|
||||
description: 'When to update the video'
|
||||
required: true
|
||||
privacy:
|
||||
type: string
|
||||
enum: [Public, Unlisted]
|
||||
description: 'Video privacy target'
|
|
@ -41,18 +41,18 @@ Uses [JavaScript Standard Style](http://standardjs.com/).
|
|||
|
||||
The server is composed by:
|
||||
|
||||
* a REST API (Express framework)
|
||||
* a WebTorrent Tracker
|
||||
* a REST API (relying on the Express framework) documented on http://docs.joinpeertube.org/api.html
|
||||
* a WebTorrent Tracker (slightly custom version of [webtorrent/bittorrent-tracker](https://github.com/webtorrent/bittorrent-tracker#server))
|
||||
|
||||
A video is seeded by the server with the [WebSeed](http://www.bittorrent.org/beps/bep_0019.html) protocol (HTTP).
|
||||
|
||||
![Architecture scheme](/support/doc/development/server/upload-video.png)
|
||||
|
||||
When a user uploads a video, the rest API create the torrent file and then adds it to its database.
|
||||
When a user uploads a video, the REST API creates the torrent file and then adds it to its database.
|
||||
|
||||
If a user wants to watch the video, the tracker will indicate all other users that are watching the video + the HTTP url for the WebSeed.
|
||||
|
||||
## Newcomers
|
||||
|
||||
The server entrypoint is [server.ts](/server.ts). You can begin to look at this file.
|
||||
Then you can try to understand the [controllers](/server/controllers): they are the entrypoint of each API request.
|
||||
The server entrypoint is [server.ts](/server.ts). Looking at this file is a good start.
|
||||
Then you can try to understand the [controllers](/server/controllers): they are the entrypoints of each API request.
|
||||
|
|
Loading…
Reference in a new issue