Sirva seu site e venda cursos com servidor auto-hospedado.
sserver é um servidor headless simples para hospedar cursos e conteúdo de blog/estático associado do repositório github privado com sobrecarga mínima.
Ele fornece https pronto para uso para que você não precise lidar com a instalação/gerenciamento de certificados. Ele sincroniza o conteúdo automaticamente do github para que você não precise fazer upload do seu conteúdo para o servidor. Ele também suporta conteúdo premium com arquivo de configuração simples sem afetar seu fluxo de trabalho de conteúdo, por exemplo, se você estiver usando um gerador de site estático como o Hugo, você pode ocultar o conteúdo premium do público especificando-o no arquivo de configuração. Possui integração de stripe para que você possa vender seu conteúdo premium. Possui gerenciamento de usuários integrado para adicionar/autenticar usuários. Também possui API de administração para que você possa monitorar pedidos/usuários do seu site.
Aqui estão alguns exemplos de como ele pode ser usado. Certifique-se de definir as variáveis de ambiente SS_<> antes de experimentá-las, por exemplo
export SS_GITHUB_TOKEN=<github_token>
export SS_STRIPE_TOKEN=<stripe_token>
export SS_SMTP_FROM=<email_id>
export SS_SMTP_USER=<smtp_username>
export SS_SMTP_PWD=<smtp_password>
export SS_SMTP_HOST=<smtp_host_address>
export SS_SMTP_PORT=<smtp_port>
export SS_ADMIN_EMAIL=<admin_email>
export SS_ADMIN_PWD=<admin_password_for_sserver>
./sserver -repo "https://github.com/newbeelearn/sserver.git"
O repositório deve ter index.html e ssconfig.toml em seu diretório raiz. Se hugo/jekyll etc., como gerador de site estático, for usado, o repositório deverá conter o site gerado. (Teria index.html na raiz por padrão)
./sserver -repo "https://github.com/newbeelearn/sserver.git?folder=public"
O repositório deve ter index.html na pasta de onde você deseja servir o conteúdo, normalmente é público se geradores de sites estáticos hugo/jekyll etc. forem usados. Deveria ter ssconfig.toml no diretório raiz
./sserver -repo "https://github.com/newbeelearn/sserver.git?ref=test-config"
Branch deve ter index.html e ssconfig.toml em seu diretório raiz. Se hugo/jekyll etc., como gerador de site estático, for usado, a ramificação deverá conter o site gerado. (Teria index.html na raiz por padrão)
./sserver -repo "https://github.com/newbeelearn/sserver.git?domain=example.com"
O repositório deve ter index.html e ssconfig.toml em seu diretório raiz Acesso ao domínio a partir do qual o site é servido sserver deve ter permissões para vincular à porta 443, isso pode ser feito com o seguinte comando
sudo setcap 'cap_net_bind_service=+ep' sserver
./sserver -repo "file:///workspace/projects/newbeelearn.com/sserver"
O repositório deve ter index.html e ssconfig.toml em seu diretório raiz. Todas as opções, ou seja, pasta/domínio, etc. também podem ser especificadas no caso de arquivos locais
O exemplo ssconfig.toml pode ser encontrado abaixo
# specify the site
[site]
# period to check for new content
syncinterval = "@every 12h"
# product/course details
[[site.prod]]
name = "course1"
# path from root, this will be accessible to users who have bought the course
path = "courses/course1"
# can be draft/active, buying functionality will be enabled when status is active
status = "active"
# unique identifier for the course
sku = "prod-course-1"
# price in cents
price = 10000
# currency
currency = "USD"
sserver cria o diretório “wwwss” de onde é executado
drwxrwxr-x 2 test test 4096 Nov 30 17:04 a
drwxrwxr-x 8 test test 4096 Nov 30 17:04 b
drwxrwxr-x 2 test test 4096 Nov 30 17:04 certs
drwxrwxr-x 2 test test 4096 Nov 30 17:04 logs
-rw-rw-r-- 1 test test 527483 Nov 30 17:04 tmp.zip
-rw-rw-r-- 1 test test 49152 Nov 30 17:05 ssapp.db
O arquivo de configuração é usado para especificar os produtos/cursos que você deseja vender, bem como alguns parâmetros do servidor, como a frequência com que o site deve ser sincronizado, etc.
Exemplo de arquivo ssconfig.toml é mostrado abaixo
#specify the site
[site]
#period to check for new content default is 12 hours
syncinterval = "@every 12h"
[[site.prod]]
name = "course1"
path = "courses/course1"
status = "active"
sku = "prod-course-1"
price = 10000
currency = "USD"
Todos os endpoints da API são relativos ao domínio usado para servir o conteúdo, ou seja, se o domínio for example.com e a API for /api/v1/product/list
a solicitação seria https://example.com/api/v1/product/list
A hierarquia de funções é assim: admin > usuário > convidado Qualquer API acessível ao convidado também é acessível ao usuário e qualquer API acessível ao usuário também é acessível ao administrador Para acessar a sessão da API do usuário/administrador, o cookie obtido após o login deve ser fornecido com cada solicitação no pratique isso será cuidado pelo navegador
Descrição | Solicitar | Papel |
---|---|---|
Cadastrar usuário | POST /api/v1/user/register | convidado |
Usuário de login | POST /api/v1/user/login | convidado |
Sair do usuário | GET /api/v1/user/logout | convidado |
Verifique o usuário | OBTER /api/v1/user/verify/:id | convidado |
Redefinir senha do usuário | POST /api/v1/user/reset | convidado |
Obtenha lista de produtos | OBTER /api/v1/product/list | convidado |
Criar pedido | POST /api/v1/order/id | convidado |
Modificar pedido | COLOQUE /api/v1/order/id | usuário |
Pedido de finalização de compra | POST /api/v1/order/checkout | usuário |
Obter pedido por ID do pedido | OBTER /api/v1/order/id/:id | usuário |
Obtenha todos os pedidos por usuário | OBTER /api/v1/order/id/list | usuário |
Alterar senha do usuário | POST /api/v1/user/changepwd | usuário |
Receba todos os pedidos | GET /api/v1/order/list | administrador |
Obtenha todos os usuários | GET /api/v1/user/list | administrador |
Cadastre novo usuário com e-mail e senha. Envia e-mail para o e-mail usado para registro com código de verificação se a configuração do servidor SMTP estiver definida.
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/user/register'
-H 'Content-Type: application/x-www-form-urlencoded'
-X POST
--data-raw 'email=stripe%40newbeelearn.com&password=test&confirm-password=test&remember=on'
Exemplo de resposta
{"status":"success"}
Login de usuário com e-mail e senha. Retorna json se o campo "postlogin" não estiver definido no arquivo de configuração, caso contrário redireciona para a página especificada em "postlogin"
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/user/login'
-H 'Content-Type: application/x-www-form-urlencoded'
-X POST
--data-raw 'email=admin%40example.com&password=admin'
Exemplo de resposta
{
"data": {
"user_id": "1",
"username": ""
},
"msg": "user found",
"status": "success"
}
Efetua logout do usuário logado e redireciona para a página inicial
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/user/logout'
-H 'Cookie: session_id=9e8b22a3-15ac-442f-bf65-15c37dbfc889; max-age=300; path=/; secure; SameSite=Lax'
Exemplo de resposta
<!doctype html>
<html lang="en">
<head>
</head>
<body>
</body>
</html>
Verifica o e-mail do usuário registrado enviando url se o domínio estiver definido ou código que deve ser anexado após a verificação da API se o domínio não estiver definido
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/user/verify/cafj5grn0gpog1j3a0m0'
Exemplo de resposta
{"status":"success"}
Redefine a senha do usuário e envia o novo código temporário para login. O usuário precisa usar este código no próximo login e alterar a senha
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/user/reset'
-H 'Content-Type: application/x-www-form-urlencoded'
-X POST
--data-raw 'email=stripe%40newbeelearn.com'
Exemplo de resposta
{
"data": null,
"msg": "password reset successful",
"status": "success"
}
Obtenha todos os produtos listados à venda no site. Aceita "limite" e "offset" como consultas. Se a consulta não for definida, os valores padrão do limite serão definidos como 10 e o deslocamento como 0
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/product/list?limit=1&offset=0'
Exemplo de resposta
{
"data": [
{
"prd_id": 1,
"prd_name": "course1",
"sku": "prod-course-1",
"permalink": "users/list/",
"price": 10000,
"currency": "USD",
"period": 365,
"status": "active"
}
],
"msg": "Order found",
"status": "success"
}
Cria novo pedido com produtos listados no campo "line_item"
. A solicitação deve ser json válida. Os campos reais order_id/user_id
etc. são preenchidos pelo servidor e qualquer valor fictício pode ser passado.
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/order/id'
-H 'Content-Type: application/json; charset=utf-8'
-H 'Cookie: session_id=cad8439e-dcc4-475e-94fc-12b75f85bb20; max-age=300; path=/; secure; SameSite=Lax'
-X POST
--data-raw ' {
"order_id": 1,
"user_id": 3,
"currency": "USD",
"line_items": [
{
"sku": "prod-course-1"
},
{
"sku": "prod-course-3"
}
]
}'
Exemplo de resposta
{
"data": {
"order_id": 1,
"user_id": 3,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"status": "active",
"currency": "USD",
"order_number": "cafjktbn0gpp5hq3dt4g",
"grand_total": 11000,
"line_items": [
{
"line_id": 1,
"order_id": 1,
"prd_id": 1,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"grand": 10000,
"enabled": true,
"sku": "prod-course-1"
},
{
"line_id": 2,
"order_id": 1,
"prd_id": 2,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"grand": 1000,
"enabled": true,
"sku": "prod-course-3"
}
]
},
"msg": "Order found",
"status": "success"
}
Modifica o pedido existente adicionando/excluindo produtos no campo line_item
. O usuário deve estar logado para modificar o pedido e o pedido deve estar no estado ativo. Use a resposta anterior de criar pedido ou obter pedido para adicionar/excluir produtos
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/order/id'
-H 'Content-Type: application/json; charset=utf-8'
-H 'Cookie: session_id=cad8439e-dcc4-475e-94fc-12b75f85bb20; max-age=300; path=/; secure; SameSite=Lax'
-X PUT
--data-raw ' {
"order_id": 1,
"user_id": 3,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"status": "active",
"currency": "USD",
"order_number": "cafjktbn0gpp5hq3dt4g",
"grand_total": 11000,
"line_items": [
{
"line_id": 2,
"order_id": 1,
"prd_id": 2,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"grand": 1000,
"enabled": true,
"sku": "prod-course-3"
}
]
}'
Exemplo de resposta
{
"data": {
"order_id": 1,
"user_id": 3,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:48:05.425488765 +0000 UTC",
"status": "active",
"currency": "USD",
"order_number": "cafjktbn0gpp5hq3dt4g",
"grand_total": 1000,
"line_items": [
{
"line_id": 2,
"order_id": 1,
"prd_id": 2,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:48:05.425488765 +0000 UTC",
"grand": 1000,
"enabled": true,
"sku": "prod-course-3"
}
]
},
"msg": "Order found",
"status": "success"
}
Obtém URL de distribuição para pagamento do pedido criado pela API de criação de pedido. Use a resposta da API criar pedido/modificar pedido/obter pedido para enviar a solicitação. Não modifique a resposta nesta solicitação, pois isso resultará em falha.
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/order/checkout'
-H 'Content-Type: application/json; charset=utf-8'
-H 'Cookie: session_id=2f1be070-7256-4e84-a4ef-c14754cabcdb; max-age=300; path=/; secure; SameSite=Lax'
-X POST
--data-raw ' {
"order_id": 1,
"user_id": 3,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"status": "active",
"currency": "USD",
"order_number": "cafjktbn0gpp5hq3dt4g",
"grand_total": 11000,
"line_items": [
{
"line_id": 2,
"order_id": 1,
"prd_id": 2,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"grand": 1000,
"enabled": true,
"sku": "prod-course-3"
}
]
}'
Exemplo de resposta
{
"data": {
"url": "https://checkout.stripe.com/pay/cs_test_a17D2l74NsKMv29YJ1c5rSBPx7BGSsNAsObGAsOanEJqyFNXKEYDLji4BZ#fidkdWxOYHwnPyd1blpxYHZxWjA0TlVKPHNMaW9vYEd1YmhdUWQ3UUJqSEpMYTMza11ObGAyXDFPcXA8bz1yY1VicVZVdDN8c1NkaUZEazxIQWdjM04wdz1DTmF3PXxHaVE9bTVuZz1pUWw3NTUybHZLZldgaicpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl"
},
"msg": "Order found",
"status": "success"
}
Obtenha detalhes do pedido por número do pedido
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/order/id/cafjktbn0gpp5hq3dt4g'
-H 'Content-Type: application/json; charset=utf-8'
-H 'Cookie: session_id=fe9b9fff-c5c0-4745-becf-ecb0e5abca81; max-age=300; path=/; secure; SameSite=Lax'
Exemplo de resposta
{
"data": {
"order_id": 1,
"user_id": 3,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:48:05.425488765 +0000 UTC",
"status": "active",
"currency": "USD",
"order_number": "cafjktbn0gpp5hq3dt4g",
"grand_total": 1000,
"line_items": [
{
"line_id": 2,
"order_id": 1,
"prd_id": 2,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:48:05.425488765 +0000 UTC",
"grand": 1000,
"enabled": true
}
]
},
"msg": "Order found",
"status": "success"
}
Obtenha todos os pedidos por usuário. Toma limite e deslocamento, pois os valores padrão dos parâmetros de consulta são 10 e 0, respectivamente
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/order/id/list?limit=1&offset=0'
-H 'Content-Type: application/json; charset=utf-8'
-H 'Cookie: session_id=fe9b9fff-c5c0-4745-becf-ecb0e5abca81; max-age=300; path=/; secure; SameSite=Lax'
Exemplo de resposta
{
"data": [
{
"order_id": 1,
"user_id": 3,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:48:05.425488765 +0000 UTC",
"status": "active",
"currency": "USD",
"order_number": "cafjktbn0gpp5hq3dt4g",
"grand_total": 1000
}
],
"msg": "Order found",
"status": "success"
}
Alterar senha do usuário. O usuário deve estar logado para fazer esta solicitação
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/user/changepwd'
-H 'Content-Type: application/x-www-form-urlencoded'
-H 'Cookie: session_id=fe9b9fff-c5c0-4745-becf-ecb0e5abca81; max-age=300; path=/; secure; SameSite=Lax'
-X POST
--data-raw 'oldpassword=cafjjjbn0gpp5hq3dt40&password=test123'
Exemplo de resposta
{
"data": null,
"msg": "password change successful",
"status": "success"
}
Obtenha todos os pedidos criados na loja. Toma limite e deslocamento, pois os valores padrão dos parâmetros de consulta são 10 e 0, respectivamente. Disponível apenas para usuários administradores. Receba todos os pedidos
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/order/list?limit=1&offset=0'
-H 'Content-Type: application/json; charset=utf-8'
-H 'Cookie: session_id=e4ecd3a4-b8be-493e-a33d-518ab11c65e8; max-age=300; path=/; secure; SameSite=Lax'
Exemplo de resposta
{
"data": [
{
"order_id": 1,
"user_id": 3,
"created_at": "2022-06-07 11:45:57.601996759 +0000 UTC",
"modified_at": "2022-06-07 11:48:05.425488765 +0000 UTC",
"status": "active",
"currency": "USD",
"order_number": "cafjktbn0gpp5hq3dt4g",
"price_total": 1000,
"discount_total": 0,
"sub_total": 1000,
"taxes_total": 0,
"grand_total": 1000,
"refunds_total": 0,
"created_channel": "",
"payment_provider": ""
}
],
"msg": "Order found",
"status": "success"
}
Obtenha todos os usuários cadastrados no site. Toma limite e deslocamento, pois os valores padrão dos parâmetros de consulta são 10 e 0, respectivamente. Disponível apenas para usuários administradores.
Exemplo de solicitação
curl 'http://localhost:54545/api/v1/user/list?limit=1&offset=0'
-H 'Content-Type: application/json; charset=utf-8'
-H 'Cookie: session_id=e4ecd3a4-b8be-493e-a33d-518ab11c65e8; max-age=300; path=/; secure; SameSite=Lax'
Exemplo de resposta
{
"data": [
{
"user_id": 1,
"email": "[email protected]",
"created_at": "2022-06-07 10:53:00.480128762 +0000 UTC",
"username": "",
"last_password_set": "2022-06-07 10:53:00.480128762 +0000 UTC",
"last_login": "2022-06-07 10:53:00.480128762 +0000 UTC",
"verified": 0,
"reset": 0,
"user_role": "admin"
},
{
"user_id": 2,
"email": "[email protected]",
"created_at": "2022-06-07 10:53:00.532691788 +0000 UTC",
"username": "",
"last_password_set": "2022-06-07 10:53:00.532691788 +0000 UTC",
"last_login": "2022-06-07 10:53:00.532691788 +0000 UTC",
"verified": 0,
"reset": 0,
"user_role": "guest"
},
{
"user_id": 3,
"email": "[email protected]",
"created_at": "2022-06-07 11:13:06.947313364 +0000 UTC",
"username": "",
"last_password_set": "2022-06-07 11:13:06.947313364 +0000 UTC",
"last_login": "2022-06-07 11:13:06.947313364 +0000 UTC",
"verified": 2,
"reset": 1,
"user_role": "user"
}
],
"msg": "Order found",
"status": "success"
}
Não, apenas binários são lançados e o site é usado para discussões sobre o produto.
Está em fase alfa, a funcionalidade está completa, mas pode conter bugs
Este foi criado devido à necessidade de sediar cursos
No momento não, porque a assinatura não é suportada, é apenas para produtos digitais únicos. Ele também não possui funcionalidade de encaminhamento de rota onde seu próprio saas pode ser conectado. No entanto, essas alterações podem ser adicionadas se houver interesse suficiente. Por favor, inicie a discussão se você gostaria de ter esses recursos a partir de agora, eles não estão no roteiro.
Ele pode ser usado para hospedar cursos e blogs associados. Blogs com boletim informativo. Blogs com conteúdo premium. Landing page da startup e blog associado. Venda de temas etc.
linux e macos são suportados imediatamente. Os usuários do Windows podem usar WSL, mas ele não foi testado.
Crie um problema e marque-o com recurso
Isso ainda não foi decidido, pois o uso é gratuito. O produto pago, se disponível, usará um canal separado. então, se você estiver baixando do github, ele será gratuito para sempre. Ajude-nos a decidir, diga-nos quanto você pagaria por isso no fórum de discussão.