Compare commits

..

5 Commits

Author SHA1 Message Date
egutierrez 8dc5db63cd mejorado para uso en servidor 2025-11-15 17:42:07 +00:00
egutierrez 233c8fefbf calendario completamente fucnional 2025-11-14 01:23:50 +01:00
egutierrez 3ca5f1b29f fondo del modal de crear evento 2025-11-14 01:05:05 +01:00
egutierrez 1e62f2a4d8 animacion difusion eliminada 2025-11-14 01:00:48 +01:00
egutierrez 4b8d400923 geestion contraseñas correcto 2025-11-14 00:29:40 +01:00
8 changed files with 147 additions and 19 deletions
+6 -1
View File
@@ -5,6 +5,11 @@
RADICALE_USERNAME=admin
RADICALE_PASSWORD=tu_contraseña_segura_aqui
# Configuración de dominios públicos (Coolify)
RADICALE_DOMAIN=radicale.tu-dominio.com
INFCLOUD_DOMAIN=infcloud.tu-dominio.com
COOLIFY_ENTRYPOINTS=https
# Configuración de Red
RADICALE_PORT=5232
INFCLOUD_PORT=8090
@@ -14,4 +19,4 @@ TZ=Europe/Madrid
# URLs base (no cambiar a menos que sepas lo que haces)
RADICALE_BASE_URL=http://localhost:5232
INFCLOUD_BASE_URL=http://localhost:8090
INFCLOUD_BASE_URL=http://localhost:8090
+16 -1
View File
@@ -70,6 +70,11 @@ INFCLOUD_PORT=8090
# Configuración de Zona Horaria
TZ=Europe/Madrid
# Dominios públicos (Coolify)
RADICALE_DOMAIN=radicale.tu-dominio.com
INFCLOUD_DOMAIN=infcloud.tu-dominio.com
COOLIFY_ENTRYPOINTS=https
# URLs base
RADICALE_BASE_URL=http://localhost:5232
INFCLOUD_BASE_URL=http://localhost:8090
@@ -130,6 +135,16 @@ docker compose restart radicale
- **Ruta principal:** /usuario/
- **SSL:** No (para desarrollo local)
## 🌐 Integración con coolify-proxy
1. **Define los dominios públicos:** Rellena las variables `RADICALE_DOMAIN`, `INFCLOUD_DOMAIN` y `COOLIFY_ENTRYPOINTS` (por defecto `https`) en `.env`. Mantén `RADICALE_BASE_URL` e `INFCLOUD_BASE_URL` apuntando a las URLs HTTPS finales para que InfCloud genere enlaces correctos.
2. **Genera la configuración de InfCloud:** `make config`.
3. **Asegura la red externa:** Coolify crea una red llamada `coolify-proxy`. Si no existe ejecútalo una vez como root: `docker network create coolify-proxy`.
4. **Ajusta y despliega los servicios:** `docker compose up -d` (o `make start`). Cada servicio se conectará automáticamente tanto a `caldav_net` como a `coolify-proxy` y expondrá las etiquetas Traefik necesarias.
5. **Verifica la conexión a la red de Coolify:** `docker network inspect coolify-proxy | grep -E 'radicale|infcloud'`.
6. **Crea los routers desde Coolify:** Dentro del panel de Coolify > Proxy, declara cada subdominio apuntando al contenedor correspondiente y al puerto interno (`5232` para Radicale, `80` para InfCloud). Traefik detectará los labels y emitirá los certificados usando el resolver indicado.
7. **Pruebas rápidas:** `docker compose ps` para comprobar que ambos contenedores están arriba y `curl -u usuario:contraseña -X PROPFIND https://tu-subdominio-radicale/usuario/ -H "Depth: 0"` para validar la publicación detrás de Coolify.
## 🐛 Resolución de Problemas
### Error 405 PROPFIND
@@ -224,4 +239,4 @@ make restart # Reiniciar servicios
**Pruebas realizadas:**
- ✅ admin: HTTP 207 Multi-Status
- ✅ user1: HTTP 207 Multi-Status
- ✅ Cualquier usuario nuevo funciona automáticamente
- ✅ Cualquier usuario nuevo funciona automáticamente
+14
View File
@@ -14,6 +14,12 @@ services:
- "${RADICALE_PORT}:5232"
networks:
- caldav_net
- coolify-proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.radicale.rule=Host(`${RADICALE_DOMAIN}`)"
- "traefik.http.routers.radicale.entrypoints=${COOLIFY_ENTRYPOINTS}"
- "traefik.http.services.radicale.loadbalancer.server.port=5232"
infcloud:
image: nginx:alpine
@@ -30,7 +36,15 @@ services:
- ./infcloud_config/nginx-simple.conf:/etc/nginx/conf.d/default.conf:ro
networks:
- caldav_net
- coolify-proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.infcloud.rule=Host(`${INFCLOUD_DOMAIN}`)"
- "traefik.http.routers.infcloud.entrypoints=${COOLIFY_ENTRYPOINTS}"
- "traefik.http.services.infcloud.loadbalancer.server.port=80"
networks:
caldav_net:
driver: bridge
coolify-proxy:
external: true
+5 -4
View File
@@ -3,7 +3,7 @@
// Configuración según documentación oficial de Radicale
// https://github.com/Kozea/Radicale/wiki/Client-InfCloud
var globalNetworkCheckSettings = {
href: 'http://localhost:8090/radicale/',
href: 'https://infcloud-h5j23io4jn45.organic-machine.com/radicale/',
timeOut: 90000,
lockTimeOut: 10000,
checkContentType: false,
@@ -28,7 +28,8 @@ var globalSearchTransformAlphabet = 'AÁÀÂàáâBCÇcçDEÉÈÊeéèêFGHIÍÌ
// Configuración de calendario
var globalCalendarSelected = '';
var globalTodoCalendarSelected = '';
var globalActiveView = 'multiWeek'; // Vista por defecto: semana múltiple
var globalActiveView = 'agendaWeek'; // Vista por defecto: semana
var globalDefaultEventDuration = 60; // Eventos nuevos duran 1 hora
var globalOpenFormMode = 'double';
var globalTodoListFilterSelected = ['filterAction', 'filterProgress', 'filterCompleted', 'filterCanceled'];
var globalActiveApp = null;
@@ -40,7 +41,7 @@ var globalDisplayHiddenEvents = false;
// Configuraciones adicionales de usuario que se recordarán
var globalUserPreferences = {
defaultView: 'multiWeek', // Vista preferida del usuario
defaultView: 'agendaWeek', // Vista preferida del usuario
showWeekends: true, // Mostrar fines de semana
firstDayOfWeek: 1, // Lunes = 1, Domingo = 0
workingHours: {start: 8, end: 18}, // Horario laboral
@@ -95,7 +96,7 @@ var globalUseCrossOrigin = false;
// Variables adicionales requeridas
var globalContactDataMinVisiblePercentage = 0.2;
var globalEditorFadeAnimation = 666;
var globalEditorFadeAnimation = 0;
var globalEventStartPastLimit = 3;
var globalEventStartFutureLimit = 3;
var globalTodoStartPastLimit = 3;
+4 -3
View File
@@ -28,7 +28,8 @@ var globalSearchTransformAlphabet = 'AÁÀÂàáâBCÇcçDEÉÈÊeéèêFGHIÍÌ
// Configuración de calendario
var globalCalendarSelected = '';
var globalTodoCalendarSelected = '';
var globalActiveView = 'multiWeek'; // Vista por defecto: semana múltiple
var globalActiveView = 'agendaWeek'; // Vista por defecto: semana
var globalDefaultEventDuration = 60; // Eventos nuevos duran 1 hora
var globalOpenFormMode = 'double';
var globalTodoListFilterSelected = ['filterAction', 'filterProgress', 'filterCompleted', 'filterCanceled'];
var globalActiveApp = null;
@@ -40,7 +41,7 @@ var globalDisplayHiddenEvents = false;
// Configuraciones adicionales de usuario que se recordarán
var globalUserPreferences = {
defaultView: 'multiWeek', // Vista preferida del usuario
defaultView: 'agendaWeek', // Vista preferida del usuario
showWeekends: true, // Mostrar fines de semana
firstDayOfWeek: 1, // Lunes = 1, Domingo = 0
workingHours: {start: 8, end: 18}, // Horario laboral
@@ -95,7 +96,7 @@ var globalUseCrossOrigin = false;
// Variables adicionales requeridas
var globalContactDataMinVisiblePercentage = 0.2;
var globalEditorFadeAnimation = 666;
var globalEditorFadeAnimation = 0;
var globalEventStartPastLimit = 3;
var globalEventStartFutureLimit = 3;
var globalTodoStartPastLimit = 3;
+12 -9
View File
@@ -298,10 +298,11 @@ body, input, select, textarea
right: 583px;
bottom: 0;
overflow: hidden;
background: #ffffff;
background: rgba(0, 0, 0, 0);
display: none;
z-index: 10;
cursor: default;
pointer-events: none;
user-select: none;
-webkit-user-select: none;
@@ -1202,10 +1203,11 @@ input.non_editable
border-right: 1px solid;
border-right-color: #c0c0c0;
width: 224px;
background: #ffffff;
background: rgba(0, 0, 0, 0);
display: none;
z-index: 10;
cursor: default;
pointer-events: none;
user-select: none;
-webkit-user-select: none;
@@ -1220,11 +1222,12 @@ input.non_editable
right: 0px;
bottom: 0px;
overflow: hidden;
background: #ffffff;
opacity: 0.8;
background: rgba(0, 0, 0, 0);
opacity: 1;
display: none;
z-index: 22;
cursor: default;
pointer-events: none;
user-select: none;
-webkit-user-select: none;
@@ -2203,15 +2206,16 @@ body
right: 0px;
bottom: 0px;
overflow: visible;
background: #ffffff;
background: rgba(0, 0, 0, 0);
display: none;
opacity: 0.8;
opacity: 1;
z-index: 99;
cursor:default;
user-select: none;
-webkit-user-select:none;
-moz-user-select: -moz-none;
pointer-events: none;
}
#CAEvent .saveLoader
@@ -2613,9 +2617,8 @@ h3
position: fixed;
width: 100%;
height: 100%;
background-color: #f9f9f9;
opacity: 0.7;
filter: alpha(opacity=70);
background-color: rgba(249, 249, 249, 0.15);
opacity: 1;
z-index: 99;
top: 0px;
left: 0px;
+70 -1
View File
@@ -17,7 +17,76 @@ GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
*/
// Disable jQuery fade animations to make UI snappier
(function (win) {
if (!win || !win.jQuery) {
return;
}
var $ = win.jQuery;
if ($.fx && $.fx.off !== true) {
$.fx.off = true;
}
if ($.fn._noAnimationPatch) {
return;
}
function getCallback(args) {
for (var i = args.length - 1; i >= 0; i--) {
if (typeof args[i] === 'function') {
return args[i];
}
}
return null;
}
function immediate(action) {
return function () {
var callback = getCallback(arguments);
return this.each(function () {
var el = $(this);
if (action === 'show') {
el.show().css('opacity', 1);
} else if (action === 'hide') {
el.hide().css('opacity', 0);
}
if (callback) {
callback.call(this);
}
});
};
}
$.fn.fadeIn = immediate('show');
$.fn.fadeOut = immediate('hide');
$.fn.fadeTo = function () {
var callback = getCallback(arguments);
var target = typeof arguments[1] === 'number' ? arguments[1] : 1;
return this.each(function () {
var el = $(this);
el.css('opacity', target);
if (target === 0) {
el.hide();
} else {
el.show();
}
if (callback) {
callback.call(this);
}
});
};
$.fn.fadeToggle = function () {
var callback = getCallback(arguments);
return this.each(function () {
var el = $(this);
var hidden = !el.is(':visible') || el.css('opacity') === '0';
if (hidden) {
el.fadeIn(callback);
} else {
el.fadeOut(callback);
}
});
};
$.fn._noAnimationPatch = true;
})(window);
var globalSettings={
version: {value: (typeof globalSettingsVersion!='undefined' && globalSettingsVersion!=null) ? globalSettingsVersion : 1, locked:false},
+20
View File
@@ -76,6 +76,26 @@ prompt_password() {
htpasswd_update() {
local user="$1" password="$2"
htpasswd -B -C "$DEFAULT_COST" -b "$USERS_FILE" "$user" "$password" >/dev/null
normalize_bcrypt_prefix "$user"
}
normalize_bcrypt_prefix() {
local user="$1"
if ! command -v python3 >/dev/null 2>&1; then
echo "⚠️ python3 no disponible: no se pudo normalizar el hash bcrypt de '$user' (prefijo \$2y\$)." >&2
echo " Radicale solo acepta hashes \$2b\$, por lo que este usuario podría fallar." >&2
return
fi
python3 - "$USERS_FILE" "$user" <<'PY'
import pathlib, re, sys
path = pathlib.Path(sys.argv[1])
user = sys.argv[2]
data = path.read_text()
pattern = re.compile(rf'^({re.escape(user)}:\$)2y', re.M)
updated, count = pattern.subn(r'\g<1>2b', data)
if count:
path.write_text(updated)
PY
}
list_users() {