11import { db } from "@dokploy/server/db" ;
22import {
33 type apiCreateDestination ,
4+ type apiCreateRcloneDestination ,
5+ type apiUpdateRcloneDestination ,
46 destinations ,
57} from "@dokploy/server/db/schema" ;
68import { TRPCError } from "@trpc/server" ;
@@ -81,3 +83,100 @@ export const updateDestinationById = async (
8183
8284 return result [ 0 ] ;
8385} ;
86+
87+ export const createRcloneDestination = async (
88+ input : z . infer < typeof apiCreateRcloneDestination > ,
89+ organizationId : string ,
90+ ) => {
91+ const newDestination = await db
92+ . insert ( destinations )
93+ . values ( {
94+ name : input . name ,
95+ // S3 required fields set to empty for rclone destinations
96+ accessKey : "" ,
97+ secretAccessKey : "" ,
98+ bucket : "" ,
99+ region : "" ,
100+ endpoint : "" ,
101+ organizationId : organizationId ,
102+ destinationType : "rclone" ,
103+ rcloneType : input . rcloneType ,
104+ rcloneConfig : input . rcloneConfig ,
105+ rcloneRemoteName : input . rcloneRemoteName ,
106+ rcloneBucket : input . rcloneBucket || "" ,
107+ rclonePath : input . rclonePath || "" ,
108+ } )
109+ . returning ( )
110+ . then ( ( value ) => value [ 0 ] ) ;
111+
112+ if ( ! newDestination ) {
113+ throw new TRPCError ( {
114+ code : "BAD_REQUEST" ,
115+ message : "Error input: Inserting rclone destination" ,
116+ } ) ;
117+ }
118+
119+ return newDestination ;
120+ } ;
121+
122+ export const updateRcloneDestinationById = async (
123+ destinationId : string ,
124+ organizationId : string ,
125+ input : z . infer < typeof apiUpdateRcloneDestination > ,
126+ ) => {
127+ const updateData : Partial < Destination > = { } ;
128+
129+ if ( input . name !== undefined ) updateData . name = input . name ;
130+ if ( input . rcloneType !== undefined ) updateData . rcloneType = input . rcloneType ;
131+ if ( input . rcloneConfig !== undefined )
132+ updateData . rcloneConfig = input . rcloneConfig ;
133+ if ( input . rcloneRemoteName !== undefined )
134+ updateData . rcloneRemoteName = input . rcloneRemoteName ;
135+ if ( input . rcloneBucket !== undefined )
136+ updateData . rcloneBucket = input . rcloneBucket ;
137+ if ( input . rclonePath !== undefined ) updateData . rclonePath = input . rclonePath ;
138+
139+ const result = await db
140+ . update ( destinations )
141+ . set ( updateData )
142+ . where (
143+ and (
144+ eq ( destinations . destinationId , destinationId ) ,
145+ eq ( destinations . organizationId , organizationId ) ,
146+ ) ,
147+ )
148+ . returning ( ) ;
149+
150+ return result [ 0 ] ;
151+ } ;
152+
153+ export const buildRcloneFlags = ( destination : Destination ) : string => {
154+ if ( destination . destinationType !== "rclone" || ! destination . rcloneConfig ) {
155+ return "" ;
156+ }
157+
158+ // rclone config flags: --config accepts a file path, but we can use
159+ // environment variable RCLONE_CONFIG_<REMOTE>_<KEY>=value pattern instead
160+ // Here we return the remote name for use in rclone commands
161+ return destination . rcloneRemoteName || "" ;
162+ } ;
163+
164+ export const getRcloneRemotePath = ( destination : Destination ) : string => {
165+ if ( destination . destinationType !== "rclone" ) {
166+ return "" ;
167+ }
168+ const remote = destination . rcloneRemoteName || "" ;
169+ const bucket = destination . rcloneBucket || "" ;
170+ const path = destination . rclonePath || "" ;
171+
172+ if ( bucket && path ) {
173+ return `${ remote } :${ bucket } /${ path } ` ;
174+ }
175+ if ( bucket ) {
176+ return `${ remote } :${ bucket } ` ;
177+ }
178+ if ( path ) {
179+ return `${ remote } :${ path } ` ;
180+ }
181+ return `${ remote } :` ;
182+ } ;
0 commit comments