mirror of
https://github.com/mattermost/focalboard.git
synced 2024-11-27 08:31:20 +02:00
Store files per workspace and root block
This commit is contained in:
parent
771be97c3e
commit
9ff340c989
@ -82,12 +82,12 @@ func (a *API) RegisterRoutes(r *mux.Router) {
|
|||||||
apiv1.HandleFunc("/login", a.handleLogin).Methods("POST")
|
apiv1.HandleFunc("/login", a.handleLogin).Methods("POST")
|
||||||
apiv1.HandleFunc("/register", a.handleRegister).Methods("POST")
|
apiv1.HandleFunc("/register", a.handleRegister).Methods("POST")
|
||||||
|
|
||||||
apiv1.HandleFunc("/files", a.sessionRequired(a.handleUploadFile)).Methods("POST")
|
apiv1.HandleFunc("/workspaces/{workspaceID}/{rootID}/files", a.sessionRequired(a.handleUploadFile)).Methods("POST")
|
||||||
|
|
||||||
// Get Files API
|
// Get Files API
|
||||||
|
|
||||||
files := r.PathPrefix("/files").Subrouter()
|
files := r.PathPrefix("/files").Subrouter()
|
||||||
files.HandleFunc("/{filename}", a.sessionRequired(a.handleServeFile)).Methods("GET")
|
files.HandleFunc("/workspaces/{workspaceID}/{rootID}/{filename}", a.attachSession(a.handleServeFile, false)).Methods("GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) RegisterAdminRoutes(r *mux.Router) {
|
func (a *API) RegisterAdminRoutes(r *mux.Router) {
|
||||||
@ -116,15 +116,47 @@ func (a *API) checkCSRFToken(r *http.Request) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *API) hasValidReadTokenForBlock(r *http.Request, container store.Container, blockID string) bool {
|
||||||
|
query := r.URL.Query()
|
||||||
|
readToken := query.Get("read_token")
|
||||||
|
|
||||||
|
if len(readToken) < 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid, err := a.app().IsValidReadToken(container, blockID, readToken)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("IsValidReadToken ERROR: %v", err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid
|
||||||
|
}
|
||||||
|
|
||||||
func (a *API) getContainerAllowingReadTokenForBlock(r *http.Request, blockID string) (*store.Container, error) {
|
func (a *API) getContainerAllowingReadTokenForBlock(r *http.Request, blockID string) (*store.Container, error) {
|
||||||
|
ctx := r.Context()
|
||||||
|
session, _ := ctx.Value("session").(*model.Session)
|
||||||
|
|
||||||
if a.WorkspaceAuthenticator == nil {
|
if a.WorkspaceAuthenticator == nil {
|
||||||
// Native auth: always use root workspace
|
// Native auth: always use root workspace
|
||||||
container := store.Container{
|
container := store.Container{
|
||||||
WorkspaceID: "",
|
WorkspaceID: "",
|
||||||
}
|
}
|
||||||
return &container, nil
|
|
||||||
|
// Has session
|
||||||
|
if session != nil {
|
||||||
|
return &container, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// No session, but has valid read token (read-only mode)
|
||||||
|
if len(blockID) > 0 && a.hasValidReadTokenForBlock(r, container, blockID) {
|
||||||
|
return &container, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("Access denied to workspace")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workspace auth
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
workspaceID := vars["workspaceID"]
|
workspaceID := vars["workspaceID"]
|
||||||
|
|
||||||
@ -137,34 +169,17 @@ func (a *API) getContainerAllowingReadTokenForBlock(r *http.Request, blockID str
|
|||||||
WorkspaceID: workspaceID,
|
WorkspaceID: workspaceID,
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := r.Context()
|
// Has session and access to workspace
|
||||||
session, _ := ctx.Value("session").(*model.Session)
|
if session != nil && a.WorkspaceAuthenticator.DoesUserHaveWorkspaceAccess(session, container.WorkspaceID) {
|
||||||
if session == nil && len(blockID) > 0 {
|
return &container, nil
|
||||||
// No session, check for read_token
|
|
||||||
query := r.URL.Query()
|
|
||||||
readToken := query.Get("read_token")
|
|
||||||
|
|
||||||
// Require read token
|
|
||||||
if len(readToken) < 1 {
|
|
||||||
return nil, errors.New("Access denied to workspace")
|
|
||||||
}
|
|
||||||
|
|
||||||
isValid, err := a.app().IsValidReadToken(container, blockID, readToken)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("IsValidReadToken ERROR: %v", err)
|
|
||||||
return nil, errors.New("Access denied to workspace")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isValid {
|
|
||||||
return nil, errors.New("Access denied to workspace")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !a.WorkspaceAuthenticator.DoesUserHaveWorkspaceAccess(session, workspaceID) {
|
|
||||||
return nil, errors.New("Access denied to workspace")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &container, nil
|
// No session, but has valid read token (read-only mode)
|
||||||
|
if len(blockID) > 0 && a.hasValidReadTokenForBlock(r, container, blockID) {
|
||||||
|
return &container, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, errors.New("Access denied to workspace")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) getContainer(r *http.Request) (*store.Container, error) {
|
func (a *API) getContainer(r *http.Request) (*store.Container, error) {
|
||||||
@ -956,7 +971,7 @@ func (a *API) handlePostWorkspaceRegenerateSignupToken(w http.ResponseWriter, r
|
|||||||
// File upload
|
// File upload
|
||||||
|
|
||||||
func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
||||||
// swagger:operation GET /files/{fileID} getFile
|
// swagger:operation GET /workspaces/{workspaceID}/{rootID}/{fileID} getFile
|
||||||
//
|
//
|
||||||
// Returns the contents of an uploaded file
|
// Returns the contents of an uploaded file
|
||||||
//
|
//
|
||||||
@ -966,6 +981,16 @@ func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
// - image/jpg
|
// - image/jpg
|
||||||
// - image/png
|
// - image/png
|
||||||
// parameters:
|
// parameters:
|
||||||
|
// - name: workspaceID
|
||||||
|
// in: path
|
||||||
|
// description: Workspace ID
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// - name: rootID
|
||||||
|
// in: path
|
||||||
|
// description: ID of the root block
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
// - name: fileID
|
// - name: fileID
|
||||||
// in: path
|
// in: path
|
||||||
// description: ID of the file
|
// description: ID of the file
|
||||||
@ -982,8 +1007,17 @@ func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
// "$ref": "#/definitions/ErrorResponse"
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
workspaceID := vars["workspaceID"]
|
||||||
|
rootID := vars["rootID"]
|
||||||
filename := vars["filename"]
|
filename := vars["filename"]
|
||||||
|
|
||||||
|
// Caller must have access to the root block's container
|
||||||
|
_, err := a.getContainerAllowingReadTokenForBlock(r, rootID)
|
||||||
|
if err != nil {
|
||||||
|
noContainerErrorResponse(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
contentType := "image/jpg"
|
contentType := "image/jpg"
|
||||||
|
|
||||||
fileExtension := strings.ToLower(filepath.Ext(filename))
|
fileExtension := strings.ToLower(filepath.Ext(filename))
|
||||||
@ -993,7 +1027,7 @@ func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set("Content-Type", contentType)
|
w.Header().Set("Content-Type", contentType)
|
||||||
|
|
||||||
filePath := a.app().GetFilePath(filename)
|
filePath := a.app().GetFilePath(workspaceID, rootID, filename)
|
||||||
http.ServeFile(w, r, filePath)
|
http.ServeFile(w, r, filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1006,9 +1040,9 @@ type FileUploadResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
||||||
// swagger:operation POST /api/v1/files uploadFile
|
// swagger:operation POST /api/v1/workspaces/{workspaceID}/{rootID}/files uploadFile
|
||||||
//
|
//
|
||||||
// Upload a binary file
|
// Upload a binary file, attached to a root block
|
||||||
//
|
//
|
||||||
// ---
|
// ---
|
||||||
// consumes:
|
// consumes:
|
||||||
@ -1016,6 +1050,16 @@ func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// parameters:
|
// parameters:
|
||||||
|
// - name: workspaceID
|
||||||
|
// in: path
|
||||||
|
// description: Workspace ID
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
|
// - name: rootID
|
||||||
|
// in: path
|
||||||
|
// description: ID of the root block
|
||||||
|
// required: true
|
||||||
|
// type: string
|
||||||
// - name: uploaded file
|
// - name: uploaded file
|
||||||
// in: formData
|
// in: formData
|
||||||
// type: file
|
// type: file
|
||||||
@ -1032,6 +1076,17 @@ func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
// schema:
|
// schema:
|
||||||
// "$ref": "#/definitions/ErrorResponse"
|
// "$ref": "#/definitions/ErrorResponse"
|
||||||
|
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
workspaceID := vars["workspaceID"]
|
||||||
|
rootID := vars["rootID"]
|
||||||
|
|
||||||
|
// Caller must have access to the root block's container
|
||||||
|
_, err := a.getContainerAllowingReadTokenForBlock(r, rootID)
|
||||||
|
if err != nil {
|
||||||
|
noContainerErrorResponse(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
file, handle, err := r.FormFile("file")
|
file, handle, err := r.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(w, "%v", err)
|
fmt.Fprintf(w, "%v", err)
|
||||||
@ -1040,7 +1095,7 @@ func (a *API) handleUploadFile(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
fileId, err := a.app().SaveFile(file, handle.Filename)
|
fileId, err := a.app().SaveFile(file, workspaceID, rootID, handle.Filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorResponse(w, http.StatusInternalServerError, "", err)
|
errorResponse(w, http.StatusInternalServerError, "", err)
|
||||||
return
|
return
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/mattermost/focalboard/server/utils"
|
"github.com/mattermost/focalboard/server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *App) SaveFile(reader io.Reader, filename string) (string, error) {
|
func (a *App) SaveFile(reader io.Reader, workspaceID, rootID, filename string) (string, error) {
|
||||||
// NOTE: File extension includes the dot
|
// NOTE: File extension includes the dot
|
||||||
fileExtension := strings.ToLower(filepath.Ext(filename))
|
fileExtension := strings.ToLower(filepath.Ext(filename))
|
||||||
if fileExtension == ".jpeg" {
|
if fileExtension == ".jpeg" {
|
||||||
@ -18,8 +18,9 @@ func (a *App) SaveFile(reader io.Reader, filename string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createdFilename := fmt.Sprintf(`%s%s`, utils.CreateGUID(), fileExtension)
|
createdFilename := fmt.Sprintf(`%s%s`, utils.CreateGUID(), fileExtension)
|
||||||
|
filePath := fmt.Sprintf(`%s/%s/%s`, workspaceID, rootID, createdFilename)
|
||||||
|
|
||||||
_, appErr := a.filesBackend.WriteFile(reader, createdFilename)
|
_, appErr := a.filesBackend.WriteFile(reader, filePath)
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
return "", errors.New("unable to store the file in the files storage")
|
return "", errors.New("unable to store the file in the files storage")
|
||||||
}
|
}
|
||||||
@ -27,8 +28,9 @@ func (a *App) SaveFile(reader io.Reader, filename string) (string, error) {
|
|||||||
return createdFilename, nil
|
return createdFilename, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetFilePath(filename string) string {
|
func (a *App) GetFilePath(workspaceID, rootID, filename string) string {
|
||||||
folderPath := a.config.FilesPath
|
folderPath := a.config.FilesPath
|
||||||
|
rootPath := filepath.Join(folderPath, workspaceID, rootID)
|
||||||
|
|
||||||
return filepath.Join(folderPath, filename)
|
return filepath.Join(rootPath, filename)
|
||||||
}
|
}
|
||||||
|
@ -3160,7 +3160,7 @@ Type of blocks to return, omit to specify all types
|
|||||||
<p class="marked">Returns the contents of an uploaded file</p>
|
<p class="marked">Returns the contents of an uploaded file</p>
|
||||||
<p></p>
|
<p></p>
|
||||||
<br />
|
<br />
|
||||||
<pre class="prettyprint language-html prettyprinted" data-type="get"><code><span class="pln">/files/{fileID}</span></code></pre>
|
<pre class="prettyprint language-html prettyprinted" data-type="get"><code><span class="pln">/workspaces/{workspaceID}/{rootID}/{fileID}</span></code></pre>
|
||||||
<p>
|
<p>
|
||||||
<h3>Usage and SDK Samples</h3>
|
<h3>Usage and SDK Samples</h3>
|
||||||
</p>
|
</p>
|
||||||
@ -3184,7 +3184,7 @@ Type of blocks to return, omit to specify all types
|
|||||||
<pre class="prettyprint"><code class="language-bsh">curl -X GET\
|
<pre class="prettyprint"><code class="language-bsh">curl -X GET\
|
||||||
-H "Authorization: [[apiKey]]"\
|
-H "Authorization: [[apiKey]]"\
|
||||||
-H "Accept: application/json,image/jpg,image/png"\
|
-H "Accept: application/json,image/jpg,image/png"\
|
||||||
"http://localhost/api/v1/files/{fileID}"</code></pre>
|
"http://localhost/api/v1/workspaces/{workspaceID}/{rootID}/{fileID}"</code></pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="examples-Default-getFile-0-java">
|
<div class="tab-pane" id="examples-Default-getFile-0-java">
|
||||||
<pre class="prettyprint"><code class="language-java">import org.openapitools.client.*;
|
<pre class="prettyprint"><code class="language-java">import org.openapitools.client.*;
|
||||||
@ -3207,10 +3207,12 @@ public class DefaultApiExample {
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
DefaultApi apiInstance = new DefaultApi();
|
DefaultApi apiInstance = new DefaultApi();
|
||||||
|
String workspaceID = workspaceID_example; // String | Workspace ID
|
||||||
|
String rootID = rootID_example; // String | ID of the root block
|
||||||
String fileID = fileID_example; // String | ID of the file
|
String fileID = fileID_example; // String | ID of the file
|
||||||
|
|
||||||
try {
|
try {
|
||||||
apiInstance.getFile(fileID);
|
apiInstance.getFile(workspaceID, rootID, fileID);
|
||||||
} catch (ApiException e) {
|
} catch (ApiException e) {
|
||||||
System.err.println("Exception when calling DefaultApi#getFile");
|
System.err.println("Exception when calling DefaultApi#getFile");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -3226,10 +3228,12 @@ public class DefaultApiExample {
|
|||||||
public class DefaultApiExample {
|
public class DefaultApiExample {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
DefaultApi apiInstance = new DefaultApi();
|
DefaultApi apiInstance = new DefaultApi();
|
||||||
|
String workspaceID = workspaceID_example; // String | Workspace ID
|
||||||
|
String rootID = rootID_example; // String | ID of the root block
|
||||||
String fileID = fileID_example; // String | ID of the file
|
String fileID = fileID_example; // String | ID of the file
|
||||||
|
|
||||||
try {
|
try {
|
||||||
apiInstance.getFile(fileID);
|
apiInstance.getFile(workspaceID, rootID, fileID);
|
||||||
} catch (ApiException e) {
|
} catch (ApiException e) {
|
||||||
System.err.println("Exception when calling DefaultApi#getFile");
|
System.err.println("Exception when calling DefaultApi#getFile");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -3252,9 +3256,13 @@ public class DefaultApiExample {
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
DefaultApi *apiInstance = [[DefaultApi alloc] init];
|
DefaultApi *apiInstance = [[DefaultApi alloc] init];
|
||||||
|
String *workspaceID = workspaceID_example; // Workspace ID (default to null)
|
||||||
|
String *rootID = rootID_example; // ID of the root block (default to null)
|
||||||
String *fileID = fileID_example; // ID of the file (default to null)
|
String *fileID = fileID_example; // ID of the file (default to null)
|
||||||
|
|
||||||
[apiInstance getFileWith:fileID
|
[apiInstance getFileWith:workspaceID
|
||||||
|
rootID:rootID
|
||||||
|
fileID:fileID
|
||||||
completionHandler: ^(NSError* error) {
|
completionHandler: ^(NSError* error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
NSLog(@"Error: %@", error);
|
NSLog(@"Error: %@", error);
|
||||||
@ -3275,6 +3283,8 @@ BearerAuth.apiKey = "YOUR API KEY";
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
var api = new FocalboardServer.DefaultApi()
|
var api = new FocalboardServer.DefaultApi()
|
||||||
|
var workspaceID = workspaceID_example; // {String} Workspace ID
|
||||||
|
var rootID = rootID_example; // {String} ID of the root block
|
||||||
var fileID = fileID_example; // {String} ID of the file
|
var fileID = fileID_example; // {String} ID of the file
|
||||||
|
|
||||||
var callback = function(error, data, response) {
|
var callback = function(error, data, response) {
|
||||||
@ -3284,7 +3294,7 @@ var callback = function(error, data, response) {
|
|||||||
console.log('API called successfully.');
|
console.log('API called successfully.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
api.getFile(fileID, callback);
|
api.getFile(workspaceID, rootID, fileID, callback);
|
||||||
</code></pre>
|
</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -3311,10 +3321,12 @@ namespace Example
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
var apiInstance = new DefaultApi();
|
var apiInstance = new DefaultApi();
|
||||||
|
var workspaceID = workspaceID_example; // String | Workspace ID (default to null)
|
||||||
|
var rootID = rootID_example; // String | ID of the root block (default to null)
|
||||||
var fileID = fileID_example; // String | ID of the file (default to null)
|
var fileID = fileID_example; // String | ID of the file (default to null)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
apiInstance.getFile(fileID);
|
apiInstance.getFile(workspaceID, rootID, fileID);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Debug.Print("Exception when calling DefaultApi.getFile: " + e.Message );
|
Debug.Print("Exception when calling DefaultApi.getFile: " + e.Message );
|
||||||
}
|
}
|
||||||
@ -3335,10 +3347,12 @@ OpenAPITools\Client\Configuration::getDefaultConfiguration()->setApiKey('Authori
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
$api_instance = new OpenAPITools\Client\Api\DefaultApi();
|
$api_instance = new OpenAPITools\Client\Api\DefaultApi();
|
||||||
|
$workspaceID = workspaceID_example; // String | Workspace ID
|
||||||
|
$rootID = rootID_example; // String | ID of the root block
|
||||||
$fileID = fileID_example; // String | ID of the file
|
$fileID = fileID_example; // String | ID of the file
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$api_instance->getFile($fileID);
|
$api_instance->getFile($workspaceID, $rootID, $fileID);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo 'Exception when calling DefaultApi->getFile: ', $e->getMessage(), PHP_EOL;
|
echo 'Exception when calling DefaultApi->getFile: ', $e->getMessage(), PHP_EOL;
|
||||||
}
|
}
|
||||||
@ -3357,10 +3371,12 @@ $WWW::OPenAPIClient::Configuration::api_key->{'Authorization'} = 'YOUR_API_KEY';
|
|||||||
|
|
||||||
# Create an instance of the API class
|
# Create an instance of the API class
|
||||||
my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
|
my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
|
||||||
|
my $workspaceID = workspaceID_example; # String | Workspace ID
|
||||||
|
my $rootID = rootID_example; # String | ID of the root block
|
||||||
my $fileID = fileID_example; # String | ID of the file
|
my $fileID = fileID_example; # String | ID of the file
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
$api_instance->getFile(fileID => $fileID);
|
$api_instance->getFile(workspaceID => $workspaceID, rootID => $rootID, fileID => $fileID);
|
||||||
};
|
};
|
||||||
if ($@) {
|
if ($@) {
|
||||||
warn "Exception when calling DefaultApi->getFile: $@\n";
|
warn "Exception when calling DefaultApi->getFile: $@\n";
|
||||||
@ -3381,10 +3397,12 @@ openapi_client.configuration.api_key['Authorization'] = 'YOUR_API_KEY'
|
|||||||
|
|
||||||
# Create an instance of the API class
|
# Create an instance of the API class
|
||||||
api_instance = openapi_client.DefaultApi()
|
api_instance = openapi_client.DefaultApi()
|
||||||
|
workspaceID = workspaceID_example # String | Workspace ID (default to null)
|
||||||
|
rootID = rootID_example # String | ID of the root block (default to null)
|
||||||
fileID = fileID_example # String | ID of the file (default to null)
|
fileID = fileID_example # String | ID of the file (default to null)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
api_instance.get_file(fileID)
|
api_instance.get_file(workspaceID, rootID, fileID)
|
||||||
except ApiException as e:
|
except ApiException as e:
|
||||||
print("Exception when calling DefaultApi->getFile: %s\n" % e)</code></pre>
|
print("Exception when calling DefaultApi->getFile: %s\n" % e)</code></pre>
|
||||||
</div>
|
</div>
|
||||||
@ -3393,10 +3411,12 @@ except ApiException as e:
|
|||||||
<pre class="prettyprint"><code class="language-rust">extern crate DefaultApi;
|
<pre class="prettyprint"><code class="language-rust">extern crate DefaultApi;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
let workspaceID = workspaceID_example; // String
|
||||||
|
let rootID = rootID_example; // String
|
||||||
let fileID = fileID_example; // String
|
let fileID = fileID_example; // String
|
||||||
|
|
||||||
let mut context = DefaultApi::Context::default();
|
let mut context = DefaultApi::Context::default();
|
||||||
let result = client.getFile(fileID, &context).wait();
|
let result = client.getFile(workspaceID, rootID, fileID, &context).wait();
|
||||||
|
|
||||||
println!("{:?}", result);
|
println!("{:?}", result);
|
||||||
}
|
}
|
||||||
@ -3417,6 +3437,52 @@ pub fn main() {
|
|||||||
<th width="150px">Name</th>
|
<th width="150px">Name</th>
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr><td style="width:150px;">workspaceID*</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="d2e199_getFile_workspaceID">
|
||||||
|
<div class="json-schema-view">
|
||||||
|
<div class="primitive">
|
||||||
|
<span class="type">
|
||||||
|
String
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="inner description marked">
|
||||||
|
Workspace ID
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="inner required">
|
||||||
|
Required
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr><td style="width:150px;">rootID*</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="d2e199_getFile_rootID">
|
||||||
|
<div class="json-schema-view">
|
||||||
|
<div class="primitive">
|
||||||
|
<span class="type">
|
||||||
|
String
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="inner description marked">
|
||||||
|
ID of the root block
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="inner required">
|
||||||
|
Required
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
<tr><td style="width:150px;">fileID*</td>
|
<tr><td style="width:150px;">fileID*</td>
|
||||||
<td>
|
<td>
|
||||||
|
|
||||||
@ -8490,10 +8556,10 @@ $(document).ready(function() {
|
|||||||
<div class="pull-right"></div>
|
<div class="pull-right"></div>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
<p></p>
|
<p></p>
|
||||||
<p class="marked">Upload a binary file</p>
|
<p class="marked">Upload a binary file, attached to a root block</p>
|
||||||
<p></p>
|
<p></p>
|
||||||
<br />
|
<br />
|
||||||
<pre class="prettyprint language-html prettyprinted" data-type="post"><code><span class="pln">/api/v1/files</span></code></pre>
|
<pre class="prettyprint language-html prettyprinted" data-type="post"><code><span class="pln">/api/v1/workspaces/{workspaceID}/{rootID}/files</span></code></pre>
|
||||||
<p>
|
<p>
|
||||||
<h3>Usage and SDK Samples</h3>
|
<h3>Usage and SDK Samples</h3>
|
||||||
</p>
|
</p>
|
||||||
@ -8518,7 +8584,7 @@ $(document).ready(function() {
|
|||||||
-H "Authorization: [[apiKey]]"\
|
-H "Authorization: [[apiKey]]"\
|
||||||
-H "Accept: application/json"\
|
-H "Accept: application/json"\
|
||||||
-H "Content-Type: multipart/form-data"\
|
-H "Content-Type: multipart/form-data"\
|
||||||
"http://localhost/api/v1/api/v1/files"</code></pre>
|
"http://localhost/api/v1/api/v1/workspaces/{workspaceID}/{rootID}/files"</code></pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="examples-Default-uploadFile-0-java">
|
<div class="tab-pane" id="examples-Default-uploadFile-0-java">
|
||||||
<pre class="prettyprint"><code class="language-java">import org.openapitools.client.*;
|
<pre class="prettyprint"><code class="language-java">import org.openapitools.client.*;
|
||||||
@ -8541,10 +8607,12 @@ public class DefaultApiExample {
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
DefaultApi apiInstance = new DefaultApi();
|
DefaultApi apiInstance = new DefaultApi();
|
||||||
|
String workspaceID = workspaceID_example; // String | Workspace ID
|
||||||
|
String rootID = rootID_example; // String | ID of the root block
|
||||||
File uploaded file = BINARY_DATA_HERE; // File | The file to upload
|
File uploaded file = BINARY_DATA_HERE; // File | The file to upload
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileUploadResponse result = apiInstance.uploadFile(uploaded file);
|
FileUploadResponse result = apiInstance.uploadFile(workspaceID, rootID, uploaded file);
|
||||||
System.out.println(result);
|
System.out.println(result);
|
||||||
} catch (ApiException e) {
|
} catch (ApiException e) {
|
||||||
System.err.println("Exception when calling DefaultApi#uploadFile");
|
System.err.println("Exception when calling DefaultApi#uploadFile");
|
||||||
@ -8561,10 +8629,12 @@ public class DefaultApiExample {
|
|||||||
public class DefaultApiExample {
|
public class DefaultApiExample {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
DefaultApi apiInstance = new DefaultApi();
|
DefaultApi apiInstance = new DefaultApi();
|
||||||
|
String workspaceID = workspaceID_example; // String | Workspace ID
|
||||||
|
String rootID = rootID_example; // String | ID of the root block
|
||||||
File uploaded file = BINARY_DATA_HERE; // File | The file to upload
|
File uploaded file = BINARY_DATA_HERE; // File | The file to upload
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileUploadResponse result = apiInstance.uploadFile(uploaded file);
|
FileUploadResponse result = apiInstance.uploadFile(workspaceID, rootID, uploaded file);
|
||||||
System.out.println(result);
|
System.out.println(result);
|
||||||
} catch (ApiException e) {
|
} catch (ApiException e) {
|
||||||
System.err.println("Exception when calling DefaultApi#uploadFile");
|
System.err.println("Exception when calling DefaultApi#uploadFile");
|
||||||
@ -8588,9 +8658,13 @@ public class DefaultApiExample {
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
DefaultApi *apiInstance = [[DefaultApi alloc] init];
|
DefaultApi *apiInstance = [[DefaultApi alloc] init];
|
||||||
|
String *workspaceID = workspaceID_example; // Workspace ID (default to null)
|
||||||
|
String *rootID = rootID_example; // ID of the root block (default to null)
|
||||||
File *uploaded file = BINARY_DATA_HERE; // The file to upload (optional) (default to null)
|
File *uploaded file = BINARY_DATA_HERE; // The file to upload (optional) (default to null)
|
||||||
|
|
||||||
[apiInstance uploadFileWith:uploaded file
|
[apiInstance uploadFileWith:workspaceID
|
||||||
|
rootID:rootID
|
||||||
|
uploaded file:uploaded file
|
||||||
completionHandler: ^(FileUploadResponse output, NSError* error) {
|
completionHandler: ^(FileUploadResponse output, NSError* error) {
|
||||||
if (output) {
|
if (output) {
|
||||||
NSLog(@"%@", output);
|
NSLog(@"%@", output);
|
||||||
@ -8614,6 +8688,8 @@ BearerAuth.apiKey = "YOUR API KEY";
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
var api = new FocalboardServer.DefaultApi()
|
var api = new FocalboardServer.DefaultApi()
|
||||||
|
var workspaceID = workspaceID_example; // {String} Workspace ID
|
||||||
|
var rootID = rootID_example; // {String} ID of the root block
|
||||||
var opts = {
|
var opts = {
|
||||||
'uploaded file': BINARY_DATA_HERE // {File} The file to upload
|
'uploaded file': BINARY_DATA_HERE // {File} The file to upload
|
||||||
};
|
};
|
||||||
@ -8625,7 +8701,7 @@ var callback = function(error, data, response) {
|
|||||||
console.log('API called successfully. Returned data: ' + data);
|
console.log('API called successfully. Returned data: ' + data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
api.uploadFile(opts, callback);
|
api.uploadFile(workspaceID, rootID, opts, callback);
|
||||||
</code></pre>
|
</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -8652,10 +8728,12 @@ namespace Example
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
var apiInstance = new DefaultApi();
|
var apiInstance = new DefaultApi();
|
||||||
|
var workspaceID = workspaceID_example; // String | Workspace ID (default to null)
|
||||||
|
var rootID = rootID_example; // String | ID of the root block (default to null)
|
||||||
var uploaded file = BINARY_DATA_HERE; // File | The file to upload (optional) (default to null)
|
var uploaded file = BINARY_DATA_HERE; // File | The file to upload (optional) (default to null)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileUploadResponse result = apiInstance.uploadFile(uploaded file);
|
FileUploadResponse result = apiInstance.uploadFile(workspaceID, rootID, uploaded file);
|
||||||
Debug.WriteLine(result);
|
Debug.WriteLine(result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Debug.Print("Exception when calling DefaultApi.uploadFile: " + e.Message );
|
Debug.Print("Exception when calling DefaultApi.uploadFile: " + e.Message );
|
||||||
@ -8677,10 +8755,12 @@ OpenAPITools\Client\Configuration::getDefaultConfiguration()->setApiKey('Authori
|
|||||||
|
|
||||||
// Create an instance of the API class
|
// Create an instance of the API class
|
||||||
$api_instance = new OpenAPITools\Client\Api\DefaultApi();
|
$api_instance = new OpenAPITools\Client\Api\DefaultApi();
|
||||||
|
$workspaceID = workspaceID_example; // String | Workspace ID
|
||||||
|
$rootID = rootID_example; // String | ID of the root block
|
||||||
$uploaded file = BINARY_DATA_HERE; // File | The file to upload
|
$uploaded file = BINARY_DATA_HERE; // File | The file to upload
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$result = $api_instance->uploadFile($uploaded file);
|
$result = $api_instance->uploadFile($workspaceID, $rootID, $uploaded file);
|
||||||
print_r($result);
|
print_r($result);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo 'Exception when calling DefaultApi->uploadFile: ', $e->getMessage(), PHP_EOL;
|
echo 'Exception when calling DefaultApi->uploadFile: ', $e->getMessage(), PHP_EOL;
|
||||||
@ -8700,10 +8780,12 @@ $WWW::OPenAPIClient::Configuration::api_key->{'Authorization'} = 'YOUR_API_KEY';
|
|||||||
|
|
||||||
# Create an instance of the API class
|
# Create an instance of the API class
|
||||||
my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
|
my $api_instance = WWW::OPenAPIClient::DefaultApi->new();
|
||||||
|
my $workspaceID = workspaceID_example; # String | Workspace ID
|
||||||
|
my $rootID = rootID_example; # String | ID of the root block
|
||||||
my $uploaded file = BINARY_DATA_HERE; # File | The file to upload
|
my $uploaded file = BINARY_DATA_HERE; # File | The file to upload
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
my $result = $api_instance->uploadFile(uploaded file => $uploaded file);
|
my $result = $api_instance->uploadFile(workspaceID => $workspaceID, rootID => $rootID, uploaded file => $uploaded file);
|
||||||
print Dumper($result);
|
print Dumper($result);
|
||||||
};
|
};
|
||||||
if ($@) {
|
if ($@) {
|
||||||
@ -8725,10 +8807,12 @@ openapi_client.configuration.api_key['Authorization'] = 'YOUR_API_KEY'
|
|||||||
|
|
||||||
# Create an instance of the API class
|
# Create an instance of the API class
|
||||||
api_instance = openapi_client.DefaultApi()
|
api_instance = openapi_client.DefaultApi()
|
||||||
|
workspaceID = workspaceID_example # String | Workspace ID (default to null)
|
||||||
|
rootID = rootID_example # String | ID of the root block (default to null)
|
||||||
uploaded file = BINARY_DATA_HERE # File | The file to upload (optional) (default to null)
|
uploaded file = BINARY_DATA_HERE # File | The file to upload (optional) (default to null)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
api_response = api_instance.upload_file(uploaded file=uploaded file)
|
api_response = api_instance.upload_file(workspaceID, rootID, uploaded file=uploaded file)
|
||||||
pprint(api_response)
|
pprint(api_response)
|
||||||
except ApiException as e:
|
except ApiException as e:
|
||||||
print("Exception when calling DefaultApi->uploadFile: %s\n" % e)</code></pre>
|
print("Exception when calling DefaultApi->uploadFile: %s\n" % e)</code></pre>
|
||||||
@ -8738,10 +8822,12 @@ except ApiException as e:
|
|||||||
<pre class="prettyprint"><code class="language-rust">extern crate DefaultApi;
|
<pre class="prettyprint"><code class="language-rust">extern crate DefaultApi;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
let workspaceID = workspaceID_example; // String
|
||||||
|
let rootID = rootID_example; // String
|
||||||
let uploaded file = BINARY_DATA_HERE; // File
|
let uploaded file = BINARY_DATA_HERE; // File
|
||||||
|
|
||||||
let mut context = DefaultApi::Context::default();
|
let mut context = DefaultApi::Context::default();
|
||||||
let result = client.uploadFile(uploaded file, &context).wait();
|
let result = client.uploadFile(workspaceID, rootID, uploaded file, &context).wait();
|
||||||
|
|
||||||
println!("{:?}", result);
|
println!("{:?}", result);
|
||||||
}
|
}
|
||||||
@ -8756,6 +8842,59 @@ pub fn main() {
|
|||||||
|
|
||||||
<h2>Parameters</h2>
|
<h2>Parameters</h2>
|
||||||
|
|
||||||
|
<div class="methodsubtabletitle">Path parameters</div>
|
||||||
|
<table id="methodsubtable">
|
||||||
|
<tr>
|
||||||
|
<th width="150px">Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
<tr><td style="width:150px;">workspaceID*</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="d2e199_uploadFile_workspaceID">
|
||||||
|
<div class="json-schema-view">
|
||||||
|
<div class="primitive">
|
||||||
|
<span class="type">
|
||||||
|
String
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="inner description marked">
|
||||||
|
Workspace ID
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="inner required">
|
||||||
|
Required
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr><td style="width:150px;">rootID*</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="d2e199_uploadFile_rootID">
|
||||||
|
<div class="json-schema-view">
|
||||||
|
<div class="primitive">
|
||||||
|
<span class="type">
|
||||||
|
String
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="inner description marked">
|
||||||
|
ID of the root block
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="inner required">
|
||||||
|
Required
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -291,30 +291,6 @@ info:
|
|||||||
title: Focalboard Server
|
title: Focalboard Server
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
paths:
|
paths:
|
||||||
/api/v1/files:
|
|
||||||
post:
|
|
||||||
consumes:
|
|
||||||
- multipart/form-data
|
|
||||||
description: Upload a binary file
|
|
||||||
operationId: uploadFile
|
|
||||||
parameters:
|
|
||||||
- description: The file to upload
|
|
||||||
in: formData
|
|
||||||
name: uploaded file
|
|
||||||
type: file
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: success
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/FileUploadResponse'
|
|
||||||
default:
|
|
||||||
description: internal error
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/ErrorResponse'
|
|
||||||
security:
|
|
||||||
- BearerAuth: []
|
|
||||||
/api/v1/login:
|
/api/v1/login:
|
||||||
post:
|
post:
|
||||||
description: Login user
|
description: Login user
|
||||||
@ -457,6 +433,40 @@ paths:
|
|||||||
$ref: '#/definitions/ErrorResponse'
|
$ref: '#/definitions/ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
|
/api/v1/workspaces/{workspaceID}/{rootID}/files:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- multipart/form-data
|
||||||
|
description: Upload a binary file, attached to a root block
|
||||||
|
operationId: uploadFile
|
||||||
|
parameters:
|
||||||
|
- description: Workspace ID
|
||||||
|
in: path
|
||||||
|
name: workspaceID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: ID of the root block
|
||||||
|
in: path
|
||||||
|
name: rootID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: The file to upload
|
||||||
|
in: formData
|
||||||
|
name: uploaded file
|
||||||
|
type: file
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: success
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/FileUploadResponse'
|
||||||
|
default:
|
||||||
|
description: internal error
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
security:
|
||||||
|
- BearerAuth: []
|
||||||
/api/v1/workspaces/{workspaceID}/blocks:
|
/api/v1/workspaces/{workspaceID}/blocks:
|
||||||
get:
|
get:
|
||||||
description: Returns blocks
|
description: Returns blocks
|
||||||
@ -714,11 +724,21 @@ paths:
|
|||||||
$ref: '#/definitions/ErrorResponse'
|
$ref: '#/definitions/ErrorResponse'
|
||||||
security:
|
security:
|
||||||
- BearerAuth: []
|
- BearerAuth: []
|
||||||
/files/{fileID}:
|
/workspaces/{workspaceID}/{rootID}/{fileID}:
|
||||||
get:
|
get:
|
||||||
description: Returns the contents of an uploaded file
|
description: Returns the contents of an uploaded file
|
||||||
operationId: getFile
|
operationId: getFile
|
||||||
parameters:
|
parameters:
|
||||||
|
- description: Workspace ID
|
||||||
|
in: path
|
||||||
|
name: workspaceID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- description: ID of the root block
|
||||||
|
in: path
|
||||||
|
name: rootID
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
- description: ID of the file
|
- description: ID of the file
|
||||||
in: path
|
in: path
|
||||||
name: fileID
|
name: fileID
|
||||||
|
@ -38,7 +38,7 @@ const AddContentMenuItem = React.memo((props:Props): JSX.Element => {
|
|||||||
name={handler.getDisplayText(intl)}
|
name={handler.getDisplayText(intl)}
|
||||||
icon={handler.getIcon()}
|
icon={handler.getIcon()}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const newBlock = await handler.createBlock()
|
const newBlock = await handler.createBlock(card.rootId)
|
||||||
newBlock.parentId = card.id
|
newBlock.parentId = card.id
|
||||||
newBlock.rootId = card.rootId
|
newBlock.rootId = card.rootId
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ function addContentMenu(card: Card, intl: IntlShape, type: BlockTypes): JSX.Elem
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function addBlock(card: Card, intl: IntlShape, handler: ContentHandler) {
|
async function addBlock(card: Card, intl: IntlShape, handler: ContentHandler) {
|
||||||
const newBlock = await handler.createBlock()
|
const newBlock = await handler.createBlock(card.rootId)
|
||||||
newBlock.parentId = card.id
|
newBlock.parentId = card.id
|
||||||
newBlock.rootId = card.rootId
|
newBlock.rootId = card.rootId
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ type ContentHandler = {
|
|||||||
type: BlockTypes,
|
type: BlockTypes,
|
||||||
getDisplayText: (intl: IntlShape) => string,
|
getDisplayText: (intl: IntlShape) => string,
|
||||||
getIcon: () => JSX.Element,
|
getIcon: () => JSX.Element,
|
||||||
createBlock: () => Promise<MutableContentBlock>,
|
createBlock: (rootId: string) => Promise<MutableContentBlock>,
|
||||||
createComponent: (block: IContentBlock, intl: IntlShape, readonly: boolean) => JSX.Element,
|
createComponent: (block: IContentBlock, intl: IntlShape, readonly: boolean) => JSX.Element,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,18 +17,18 @@ type Props = {
|
|||||||
const ImageElement = React.memo((props: Props): JSX.Element|null => {
|
const ImageElement = React.memo((props: Props): JSX.Element|null => {
|
||||||
const [imageDataUrl, setImageDataUrl] = useState<string|null>(null)
|
const [imageDataUrl, setImageDataUrl] = useState<string|null>(null)
|
||||||
|
|
||||||
|
const {block} = props
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!imageDataUrl) {
|
if (!imageDataUrl) {
|
||||||
const loadImage = async () => {
|
const loadImage = async () => {
|
||||||
const url = await octoClient.getFileAsDataUrl(props.block.fields.fileId)
|
const url = await octoClient.getFileAsDataUrl(block.rootId, props.block.fields.fileId)
|
||||||
setImageDataUrl(url)
|
setImageDataUrl(url)
|
||||||
}
|
}
|
||||||
loadImage()
|
loadImage()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const {block} = props
|
|
||||||
|
|
||||||
if (!imageDataUrl) {
|
if (!imageDataUrl) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@ -45,11 +45,11 @@ contentRegistry.registerContentType({
|
|||||||
type: 'image',
|
type: 'image',
|
||||||
getDisplayText: (intl) => intl.formatMessage({id: 'ContentBlock.image', defaultMessage: 'image'}),
|
getDisplayText: (intl) => intl.formatMessage({id: 'ContentBlock.image', defaultMessage: 'image'}),
|
||||||
getIcon: () => <ImageIcon/>,
|
getIcon: () => <ImageIcon/>,
|
||||||
createBlock: async () => {
|
createBlock: async (rootId: string) => {
|
||||||
return new Promise<MutableImageBlock>(
|
return new Promise<MutableImageBlock>(
|
||||||
(resolve) => {
|
(resolve) => {
|
||||||
Utils.selectLocalFile(async (file) => {
|
Utils.selectLocalFile(async (file) => {
|
||||||
const fileId = await octoClient.uploadFile(file)
|
const fileId = await octoClient.uploadFile(rootId, file)
|
||||||
|
|
||||||
const block = new MutableImageBlock()
|
const block = new MutableImageBlock()
|
||||||
block.fileId = fileId || ''
|
block.fileId = fileId || ''
|
||||||
|
@ -592,31 +592,6 @@ class Mutator {
|
|||||||
return octoClient.importFullArchive(blocks)
|
return octoClient.importFullArchive(blocks)
|
||||||
}
|
}
|
||||||
|
|
||||||
async createImageBlock(parent: IBlock, file: File, description = 'add image'): Promise<IBlock | undefined> {
|
|
||||||
const fileId = await octoClient.uploadFile(file)
|
|
||||||
if (!fileId) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
const block = new MutableImageBlock()
|
|
||||||
block.parentId = parent.id
|
|
||||||
block.rootId = parent.rootId
|
|
||||||
block.fileId = fileId
|
|
||||||
|
|
||||||
await undoManager.perform(
|
|
||||||
async () => {
|
|
||||||
await octoClient.insertBlock(block)
|
|
||||||
},
|
|
||||||
async () => {
|
|
||||||
await octoClient.deleteBlock(block.id)
|
|
||||||
},
|
|
||||||
description,
|
|
||||||
this.undoGroupId,
|
|
||||||
)
|
|
||||||
|
|
||||||
return block
|
|
||||||
}
|
|
||||||
|
|
||||||
get canUndo(): boolean {
|
get canUndo(): boolean {
|
||||||
return undoManager.canUndo
|
return undoManager.canUndo
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ class OctoClient {
|
|||||||
set token(value: string) {
|
set token(value: string) {
|
||||||
localStorage.setItem('sessionId', value)
|
localStorage.setItem('sessionId', value)
|
||||||
}
|
}
|
||||||
get readToken(): string {
|
|
||||||
|
private readToken(): string {
|
||||||
const queryString = new URLSearchParams(window.location.search)
|
const queryString = new URLSearchParams(window.location.search)
|
||||||
const readToken = queryString.get('r') || ''
|
const readToken = queryString.get('r') || ''
|
||||||
return readToken
|
return readToken
|
||||||
@ -123,8 +124,9 @@ class OctoClient {
|
|||||||
|
|
||||||
async getSubtree(rootId?: string, levels = 2): Promise<IBlock[]> {
|
async getSubtree(rootId?: string, levels = 2): Promise<IBlock[]> {
|
||||||
let path = this.workspacePath() + `/blocks/${encodeURIComponent(rootId || '')}/subtree?l=${levels}`
|
let path = this.workspacePath() + `/blocks/${encodeURIComponent(rootId || '')}/subtree?l=${levels}`
|
||||||
if (this.readToken) {
|
const readToken = this.readToken()
|
||||||
path += `&read_token=${this.readToken}`
|
if (readToken) {
|
||||||
|
path += `&read_token=${readToken}`
|
||||||
}
|
}
|
||||||
const response = await fetch(this.serverUrl + path, {headers: this.headers()})
|
const response = await fetch(this.serverUrl + path, {headers: this.headers()})
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
@ -308,7 +310,7 @@ class OctoClient {
|
|||||||
// Files
|
// Files
|
||||||
|
|
||||||
// Returns fileId of uploaded file, or undefined on failure
|
// Returns fileId of uploaded file, or undefined on failure
|
||||||
async uploadFile(file: File): Promise<string | undefined> {
|
async uploadFile(rootID: string, file: File): Promise<string | undefined> {
|
||||||
// IMPORTANT: We need to post the image as a form. The browser will convert this to a application/x-www-form-urlencoded POST
|
// IMPORTANT: We need to post the image as a form. The browser will convert this to a application/x-www-form-urlencoded POST
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('file', file)
|
formData.append('file', file)
|
||||||
@ -319,7 +321,7 @@ class OctoClient {
|
|||||||
// TIPTIP: Leave out Content-Type here, it will be automatically set by the browser
|
// TIPTIP: Leave out Content-Type here, it will be automatically set by the browser
|
||||||
delete headers['Content-Type']
|
delete headers['Content-Type']
|
||||||
|
|
||||||
const response = await fetch(this.serverUrl + '/api/v1/files', {
|
const response = await fetch(this.serverUrl + this.workspacePath() + '/' + rootID + '/files', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers,
|
headers,
|
||||||
body: formData,
|
body: formData,
|
||||||
@ -345,8 +347,12 @@ class OctoClient {
|
|||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
async getFileAsDataUrl(fileId: string): Promise<string> {
|
async getFileAsDataUrl(rootId: string, fileId: string): Promise<string> {
|
||||||
const path = '/files/' + fileId
|
let path = '/files/workspaces/' + this.workspaceId + '/' + rootId + '/' + fileId
|
||||||
|
const readToken = this.readToken()
|
||||||
|
if (readToken) {
|
||||||
|
path += `?read_token=${readToken}`
|
||||||
|
}
|
||||||
const response = await fetch(this.serverUrl + path, {headers: this.headers()})
|
const response = await fetch(this.serverUrl + path, {headers: this.headers()})
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
return ''
|
return ''
|
||||||
|
Loading…
Reference in New Issue
Block a user